LLVM API Documentation
00001 //===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file implements the Windows specific implementation of the Path API. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 //===----------------------------------------------------------------------===// 00015 //=== WARNING: Implementation here must contain only generic Windows code that 00016 //=== is guaranteed to work on *all* Windows variants. 00017 //===----------------------------------------------------------------------===// 00018 00019 #include "llvm/ADT/STLExtras.h" 00020 #include "llvm/Support/WindowsError.h" 00021 #include <fcntl.h> 00022 #include <io.h> 00023 #include <sys/stat.h> 00024 #include <sys/types.h> 00025 00026 // These two headers must be included last, and make sure shlobj is required 00027 // after Windows.h to make sure it picks up our definition of _WIN32_WINNT 00028 #include "WindowsSupport.h" 00029 #include <shlobj.h> 00030 00031 #undef max 00032 00033 // MinGW doesn't define this. 00034 #ifndef _ERRNO_T_DEFINED 00035 #define _ERRNO_T_DEFINED 00036 typedef int errno_t; 00037 #endif 00038 00039 #ifdef _MSC_VER 00040 # pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. 00041 #endif 00042 00043 using namespace llvm; 00044 00045 using llvm::sys::windows::UTF8ToUTF16; 00046 using llvm::sys::windows::UTF16ToUTF8; 00047 00048 static std::error_code windows_error(DWORD E) { 00049 return mapWindowsError(E); 00050 } 00051 00052 static bool is_separator(const wchar_t value) { 00053 switch (value) { 00054 case L'\\': 00055 case L'/': 00056 return true; 00057 default: 00058 return false; 00059 } 00060 } 00061 00062 namespace llvm { 00063 namespace sys { 00064 namespace fs { 00065 00066 std::string getMainExecutable(const char *argv0, void *MainExecAddr) { 00067 SmallVector<wchar_t, MAX_PATH> PathName; 00068 DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); 00069 00070 // A zero return value indicates a failure other than insufficient space. 00071 if (Size == 0) 00072 return ""; 00073 00074 // Insufficient space is determined by a return value equal to the size of 00075 // the buffer passed in. 00076 if (Size == PathName.capacity()) 00077 return ""; 00078 00079 // On success, GetModuleFileNameW returns the number of characters written to 00080 // the buffer not including the NULL terminator. 00081 PathName.set_size(Size); 00082 00083 // Convert the result from UTF-16 to UTF-8. 00084 SmallVector<char, MAX_PATH> PathNameUTF8; 00085 if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) 00086 return ""; 00087 00088 return std::string(PathNameUTF8.data()); 00089 } 00090 00091 UniqueID file_status::getUniqueID() const { 00092 // The file is uniquely identified by the volume serial number along 00093 // with the 64-bit file identifier. 00094 uint64_t FileID = (static_cast<uint64_t>(FileIndexHigh) << 32ULL) | 00095 static_cast<uint64_t>(FileIndexLow); 00096 00097 return UniqueID(VolumeSerialNumber, FileID); 00098 } 00099 00100 TimeValue file_status::getLastModificationTime() const { 00101 ULARGE_INTEGER UI; 00102 UI.LowPart = LastWriteTimeLow; 00103 UI.HighPart = LastWriteTimeHigh; 00104 00105 TimeValue Ret; 00106 Ret.fromWin32Time(UI.QuadPart); 00107 return Ret; 00108 } 00109 00110 std::error_code current_path(SmallVectorImpl<char> &result) { 00111 SmallVector<wchar_t, MAX_PATH> cur_path; 00112 DWORD len = MAX_PATH; 00113 00114 do { 00115 cur_path.reserve(len); 00116 len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); 00117 00118 // A zero return value indicates a failure other than insufficient space. 00119 if (len == 0) 00120 return windows_error(::GetLastError()); 00121 00122 // If there's insufficient space, the len returned is larger than the len 00123 // given. 00124 } while (len > cur_path.capacity()); 00125 00126 // On success, GetCurrentDirectoryW returns the number of characters not 00127 // including the null-terminator. 00128 cur_path.set_size(len); 00129 return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); 00130 } 00131 00132 std::error_code create_directory(const Twine &path, bool IgnoreExisting) { 00133 SmallString<128> path_storage; 00134 SmallVector<wchar_t, 128> path_utf16; 00135 00136 if (std::error_code ec = 00137 UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) 00138 return ec; 00139 00140 if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { 00141 DWORD LastError = ::GetLastError(); 00142 if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) 00143 return windows_error(LastError); 00144 } 00145 00146 return std::error_code(); 00147 } 00148 00149 // We can't use symbolic links for windows. 00150 std::error_code create_link(const Twine &to, const Twine &from) { 00151 // Get arguments. 00152 SmallString<128> from_storage; 00153 SmallString<128> to_storage; 00154 StringRef f = from.toStringRef(from_storage); 00155 StringRef t = to.toStringRef(to_storage); 00156 00157 // Convert to utf-16. 00158 SmallVector<wchar_t, 128> wide_from; 00159 SmallVector<wchar_t, 128> wide_to; 00160 if (std::error_code ec = UTF8ToUTF16(f, wide_from)) 00161 return ec; 00162 if (std::error_code ec = UTF8ToUTF16(t, wide_to)) 00163 return ec; 00164 00165 if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) 00166 return windows_error(::GetLastError()); 00167 00168 return std::error_code(); 00169 } 00170 00171 std::error_code remove(const Twine &path, bool IgnoreNonExisting) { 00172 SmallString<128> path_storage; 00173 SmallVector<wchar_t, 128> path_utf16; 00174 00175 file_status ST; 00176 if (std::error_code EC = status(path, ST)) { 00177 if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) 00178 return EC; 00179 return std::error_code(); 00180 } 00181 00182 if (std::error_code ec = 00183 UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) 00184 return ec; 00185 00186 if (ST.type() == file_type::directory_file) { 00187 if (!::RemoveDirectoryW(c_str(path_utf16))) { 00188 std::error_code EC = windows_error(::GetLastError()); 00189 if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) 00190 return EC; 00191 } 00192 return std::error_code(); 00193 } 00194 if (!::DeleteFileW(c_str(path_utf16))) { 00195 std::error_code EC = windows_error(::GetLastError()); 00196 if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) 00197 return EC; 00198 } 00199 return std::error_code(); 00200 } 00201 00202 std::error_code rename(const Twine &from, const Twine &to) { 00203 // Get arguments. 00204 SmallString<128> from_storage; 00205 SmallString<128> to_storage; 00206 StringRef f = from.toStringRef(from_storage); 00207 StringRef t = to.toStringRef(to_storage); 00208 00209 // Convert to utf-16. 00210 SmallVector<wchar_t, 128> wide_from; 00211 SmallVector<wchar_t, 128> wide_to; 00212 if (std::error_code ec = UTF8ToUTF16(f, wide_from)) 00213 return ec; 00214 if (std::error_code ec = UTF8ToUTF16(t, wide_to)) 00215 return ec; 00216 00217 std::error_code ec = std::error_code(); 00218 for (int i = 0; i < 2000; i++) { 00219 if (::MoveFileExW(wide_from.begin(), wide_to.begin(), 00220 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) 00221 return std::error_code(); 00222 DWORD LastError = ::GetLastError(); 00223 if (LastError != ERROR_ACCESS_DENIED) 00224 break; 00225 // Retry MoveFile() at ACCESS_DENIED. 00226 // System scanners (eg. indexer) might open the source file when 00227 // It is written and closed. 00228 ::Sleep(1); 00229 } 00230 00231 return ec; 00232 } 00233 00234 std::error_code resize_file(const Twine &path, uint64_t size) { 00235 SmallString<128> path_storage; 00236 SmallVector<wchar_t, 128> path_utf16; 00237 00238 if (std::error_code ec = 00239 UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) 00240 return ec; 00241 00242 int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE); 00243 if (fd == -1) 00244 return std::error_code(errno, std::generic_category()); 00245 #ifdef HAVE__CHSIZE_S 00246 errno_t error = ::_chsize_s(fd, size); 00247 #else 00248 errno_t error = ::_chsize(fd, size); 00249 #endif 00250 ::close(fd); 00251 return std::error_code(error, std::generic_category()); 00252 } 00253 00254 std::error_code access(const Twine &Path, AccessMode Mode) { 00255 SmallString<128> PathStorage; 00256 SmallVector<wchar_t, 128> PathUtf16; 00257 00258 if (std::error_code EC = 00259 UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) 00260 return EC; 00261 00262 DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); 00263 00264 if (Attributes == INVALID_FILE_ATTRIBUTES) { 00265 // See if the file didn't actually exist. 00266 DWORD LastError = ::GetLastError(); 00267 if (LastError != ERROR_FILE_NOT_FOUND && 00268 LastError != ERROR_PATH_NOT_FOUND) 00269 return windows_error(LastError); 00270 return errc::no_such_file_or_directory; 00271 } 00272 00273 if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) 00274 return errc::permission_denied; 00275 00276 return std::error_code(); 00277 } 00278 00279 bool equivalent(file_status A, file_status B) { 00280 assert(status_known(A) && status_known(B)); 00281 return A.FileIndexHigh == B.FileIndexHigh && 00282 A.FileIndexLow == B.FileIndexLow && 00283 A.FileSizeHigh == B.FileSizeHigh && 00284 A.FileSizeLow == B.FileSizeLow && 00285 A.LastWriteTimeHigh == B.LastWriteTimeHigh && 00286 A.LastWriteTimeLow == B.LastWriteTimeLow && 00287 A.VolumeSerialNumber == B.VolumeSerialNumber; 00288 } 00289 00290 std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { 00291 file_status fsA, fsB; 00292 if (std::error_code ec = status(A, fsA)) 00293 return ec; 00294 if (std::error_code ec = status(B, fsB)) 00295 return ec; 00296 result = equivalent(fsA, fsB); 00297 return std::error_code(); 00298 } 00299 00300 static bool isReservedName(StringRef path) { 00301 // This list of reserved names comes from MSDN, at: 00302 // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx 00303 static const char *sReservedNames[] = { "nul", "con", "prn", "aux", 00304 "com1", "com2", "com3", "com4", "com5", "com6", 00305 "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", 00306 "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; 00307 00308 // First, check to see if this is a device namespace, which always 00309 // starts with \\.\, since device namespaces are not legal file paths. 00310 if (path.startswith("\\\\.\\")) 00311 return true; 00312 00313 // Then compare against the list of ancient reserved names 00314 for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { 00315 if (path.equals_lower(sReservedNames[i])) 00316 return true; 00317 } 00318 00319 // The path isn't what we consider reserved. 00320 return false; 00321 } 00322 00323 static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { 00324 if (FileHandle == INVALID_HANDLE_VALUE) 00325 goto handle_status_error; 00326 00327 switch (::GetFileType(FileHandle)) { 00328 default: 00329 llvm_unreachable("Don't know anything about this file type"); 00330 case FILE_TYPE_UNKNOWN: { 00331 DWORD Err = ::GetLastError(); 00332 if (Err != NO_ERROR) 00333 return windows_error(Err); 00334 Result = file_status(file_type::type_unknown); 00335 return std::error_code(); 00336 } 00337 case FILE_TYPE_DISK: 00338 break; 00339 case FILE_TYPE_CHAR: 00340 Result = file_status(file_type::character_file); 00341 return std::error_code(); 00342 case FILE_TYPE_PIPE: 00343 Result = file_status(file_type::fifo_file); 00344 return std::error_code(); 00345 } 00346 00347 BY_HANDLE_FILE_INFORMATION Info; 00348 if (!::GetFileInformationByHandle(FileHandle, &Info)) 00349 goto handle_status_error; 00350 00351 { 00352 file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 00353 ? file_type::directory_file 00354 : file_type::regular_file; 00355 Result = 00356 file_status(Type, Info.ftLastWriteTime.dwHighDateTime, 00357 Info.ftLastWriteTime.dwLowDateTime, 00358 Info.dwVolumeSerialNumber, Info.nFileSizeHigh, 00359 Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); 00360 return std::error_code(); 00361 } 00362 00363 handle_status_error: 00364 DWORD LastError = ::GetLastError(); 00365 if (LastError == ERROR_FILE_NOT_FOUND || 00366 LastError == ERROR_PATH_NOT_FOUND) 00367 Result = file_status(file_type::file_not_found); 00368 else if (LastError == ERROR_SHARING_VIOLATION) 00369 Result = file_status(file_type::type_unknown); 00370 else 00371 Result = file_status(file_type::status_error); 00372 return windows_error(LastError); 00373 } 00374 00375 std::error_code status(const Twine &path, file_status &result) { 00376 SmallString<128> path_storage; 00377 SmallVector<wchar_t, 128> path_utf16; 00378 00379 StringRef path8 = path.toStringRef(path_storage); 00380 if (isReservedName(path8)) { 00381 result = file_status(file_type::character_file); 00382 return std::error_code(); 00383 } 00384 00385 if (std::error_code ec = UTF8ToUTF16(path8, path_utf16)) 00386 return ec; 00387 00388 DWORD attr = ::GetFileAttributesW(path_utf16.begin()); 00389 if (attr == INVALID_FILE_ATTRIBUTES) 00390 return getStatus(INVALID_HANDLE_VALUE, result); 00391 00392 // Handle reparse points. 00393 if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { 00394 ScopedFileHandle h( 00395 ::CreateFileW(path_utf16.begin(), 00396 0, // Attributes only. 00397 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 00398 NULL, 00399 OPEN_EXISTING, 00400 FILE_FLAG_BACKUP_SEMANTICS, 00401 0)); 00402 if (!h) 00403 return getStatus(INVALID_HANDLE_VALUE, result); 00404 } 00405 00406 ScopedFileHandle h( 00407 ::CreateFileW(path_utf16.begin(), 0, // Attributes only. 00408 FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 00409 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); 00410 if (!h) 00411 return getStatus(INVALID_HANDLE_VALUE, result); 00412 00413 return getStatus(h, result); 00414 } 00415 00416 std::error_code status(int FD, file_status &Result) { 00417 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 00418 return getStatus(FileHandle, Result); 00419 } 00420 00421 std::error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { 00422 ULARGE_INTEGER UI; 00423 UI.QuadPart = Time.toWin32Time(); 00424 FILETIME FT; 00425 FT.dwLowDateTime = UI.LowPart; 00426 FT.dwHighDateTime = UI.HighPart; 00427 HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); 00428 if (!SetFileTime(FileHandle, NULL, &FT, &FT)) 00429 return windows_error(::GetLastError()); 00430 return std::error_code(); 00431 } 00432 00433 std::error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { 00434 FileDescriptor = FD; 00435 // Make sure that the requested size fits within SIZE_T. 00436 if (Size > std::numeric_limits<SIZE_T>::max()) { 00437 if (FileDescriptor) { 00438 if (CloseFD) 00439 _close(FileDescriptor); 00440 } else 00441 ::CloseHandle(FileHandle); 00442 return make_error_code(errc::invalid_argument); 00443 } 00444 00445 DWORD flprotect; 00446 switch (Mode) { 00447 case readonly: flprotect = PAGE_READONLY; break; 00448 case readwrite: flprotect = PAGE_READWRITE; break; 00449 case priv: flprotect = PAGE_WRITECOPY; break; 00450 } 00451 00452 FileMappingHandle = 00453 ::CreateFileMappingW(FileHandle, 0, flprotect, 00454 (Offset + Size) >> 32, 00455 (Offset + Size) & 0xffffffff, 00456 0); 00457 if (FileMappingHandle == NULL) { 00458 std::error_code ec = windows_error(GetLastError()); 00459 if (FileDescriptor) { 00460 if (CloseFD) 00461 _close(FileDescriptor); 00462 } else 00463 ::CloseHandle(FileHandle); 00464 return ec; 00465 } 00466 00467 DWORD dwDesiredAccess; 00468 switch (Mode) { 00469 case readonly: dwDesiredAccess = FILE_MAP_READ; break; 00470 case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; 00471 case priv: dwDesiredAccess = FILE_MAP_COPY; break; 00472 } 00473 Mapping = ::MapViewOfFile(FileMappingHandle, 00474 dwDesiredAccess, 00475 Offset >> 32, 00476 Offset & 0xffffffff, 00477 Size); 00478 if (Mapping == NULL) { 00479 std::error_code ec = windows_error(GetLastError()); 00480 ::CloseHandle(FileMappingHandle); 00481 if (FileDescriptor) { 00482 if (CloseFD) 00483 _close(FileDescriptor); 00484 } else 00485 ::CloseHandle(FileHandle); 00486 return ec; 00487 } 00488 00489 if (Size == 0) { 00490 MEMORY_BASIC_INFORMATION mbi; 00491 SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); 00492 if (Result == 0) { 00493 std::error_code ec = windows_error(GetLastError()); 00494 ::UnmapViewOfFile(Mapping); 00495 ::CloseHandle(FileMappingHandle); 00496 if (FileDescriptor) { 00497 if (CloseFD) 00498 _close(FileDescriptor); 00499 } else 00500 ::CloseHandle(FileHandle); 00501 return ec; 00502 } 00503 Size = mbi.RegionSize; 00504 } 00505 00506 // Close all the handles except for the view. It will keep the other handles 00507 // alive. 00508 ::CloseHandle(FileMappingHandle); 00509 if (FileDescriptor) { 00510 if (CloseFD) 00511 _close(FileDescriptor); // Also closes FileHandle. 00512 } else 00513 ::CloseHandle(FileHandle); 00514 return std::error_code(); 00515 } 00516 00517 mapped_file_region::mapped_file_region(const Twine &path, 00518 mapmode mode, 00519 uint64_t length, 00520 uint64_t offset, 00521 std::error_code &ec) 00522 : Mode(mode) 00523 , Size(length) 00524 , Mapping() 00525 , FileDescriptor() 00526 , FileHandle(INVALID_HANDLE_VALUE) 00527 , FileMappingHandle() { 00528 SmallString<128> path_storage; 00529 SmallVector<wchar_t, 128> path_utf16; 00530 00531 // Convert path to UTF-16. 00532 if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))) 00533 return; 00534 00535 // Get file handle for creating a file mapping. 00536 FileHandle = ::CreateFileW(c_str(path_utf16), 00537 Mode == readonly ? GENERIC_READ 00538 : GENERIC_READ | GENERIC_WRITE, 00539 Mode == readonly ? FILE_SHARE_READ 00540 : 0, 00541 0, 00542 Mode == readonly ? OPEN_EXISTING 00543 : OPEN_ALWAYS, 00544 Mode == readonly ? FILE_ATTRIBUTE_READONLY 00545 : FILE_ATTRIBUTE_NORMAL, 00546 0); 00547 if (FileHandle == INVALID_HANDLE_VALUE) { 00548 ec = windows_error(::GetLastError()); 00549 return; 00550 } 00551 00552 FileDescriptor = 0; 00553 ec = init(FileDescriptor, true, offset); 00554 if (ec) { 00555 Mapping = FileMappingHandle = 0; 00556 FileHandle = INVALID_HANDLE_VALUE; 00557 FileDescriptor = 0; 00558 } 00559 } 00560 00561 mapped_file_region::mapped_file_region(int fd, 00562 bool closefd, 00563 mapmode mode, 00564 uint64_t length, 00565 uint64_t offset, 00566 std::error_code &ec) 00567 : Mode(mode) 00568 , Size(length) 00569 , Mapping() 00570 , FileDescriptor(fd) 00571 , FileHandle(INVALID_HANDLE_VALUE) 00572 , FileMappingHandle() { 00573 FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); 00574 if (FileHandle == INVALID_HANDLE_VALUE) { 00575 if (closefd) 00576 _close(FileDescriptor); 00577 FileDescriptor = 0; 00578 ec = make_error_code(errc::bad_file_descriptor); 00579 return; 00580 } 00581 00582 ec = init(FileDescriptor, closefd, offset); 00583 if (ec) { 00584 Mapping = FileMappingHandle = 0; 00585 FileHandle = INVALID_HANDLE_VALUE; 00586 FileDescriptor = 0; 00587 } 00588 } 00589 00590 mapped_file_region::~mapped_file_region() { 00591 if (Mapping) 00592 ::UnmapViewOfFile(Mapping); 00593 } 00594 00595 mapped_file_region::mapped_file_region(mapped_file_region &&other) 00596 : Mode(other.Mode) 00597 , Size(other.Size) 00598 , Mapping(other.Mapping) 00599 , FileDescriptor(other.FileDescriptor) 00600 , FileHandle(other.FileHandle) 00601 , FileMappingHandle(other.FileMappingHandle) { 00602 other.Mapping = other.FileMappingHandle = 0; 00603 other.FileHandle = INVALID_HANDLE_VALUE; 00604 other.FileDescriptor = 0; 00605 } 00606 00607 mapped_file_region::mapmode mapped_file_region::flags() const { 00608 assert(Mapping && "Mapping failed but used anyway!"); 00609 return Mode; 00610 } 00611 00612 uint64_t mapped_file_region::size() const { 00613 assert(Mapping && "Mapping failed but used anyway!"); 00614 return Size; 00615 } 00616 00617 char *mapped_file_region::data() const { 00618 assert(Mode != readonly && "Cannot get non-const data for readonly mapping!"); 00619 assert(Mapping && "Mapping failed but used anyway!"); 00620 return reinterpret_cast<char*>(Mapping); 00621 } 00622 00623 const char *mapped_file_region::const_data() const { 00624 assert(Mapping && "Mapping failed but used anyway!"); 00625 return reinterpret_cast<const char*>(Mapping); 00626 } 00627 00628 int mapped_file_region::alignment() { 00629 SYSTEM_INFO SysInfo; 00630 ::GetSystemInfo(&SysInfo); 00631 return SysInfo.dwAllocationGranularity; 00632 } 00633 00634 std::error_code detail::directory_iterator_construct(detail::DirIterState &it, 00635 StringRef path){ 00636 SmallVector<wchar_t, 128> path_utf16; 00637 00638 if (std::error_code ec = UTF8ToUTF16(path, path_utf16)) 00639 return ec; 00640 00641 // Convert path to the format that Windows is happy with. 00642 if (path_utf16.size() > 0 && 00643 !is_separator(path_utf16[path.size() - 1]) && 00644 path_utf16[path.size() - 1] != L':') { 00645 path_utf16.push_back(L'\\'); 00646 path_utf16.push_back(L'*'); 00647 } else { 00648 path_utf16.push_back(L'*'); 00649 } 00650 00651 // Get the first directory entry. 00652 WIN32_FIND_DATAW FirstFind; 00653 ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); 00654 if (!FindHandle) 00655 return windows_error(::GetLastError()); 00656 00657 size_t FilenameLen = ::wcslen(FirstFind.cFileName); 00658 while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || 00659 (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && 00660 FirstFind.cFileName[1] == L'.')) 00661 if (!::FindNextFileW(FindHandle, &FirstFind)) { 00662 DWORD LastError = ::GetLastError(); 00663 // Check for end. 00664 if (LastError == ERROR_NO_MORE_FILES) 00665 return detail::directory_iterator_destruct(it); 00666 return windows_error(LastError); 00667 } else 00668 FilenameLen = ::wcslen(FirstFind.cFileName); 00669 00670 // Construct the current directory entry. 00671 SmallString<128> directory_entry_name_utf8; 00672 if (std::error_code ec = 00673 UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), 00674 directory_entry_name_utf8)) 00675 return ec; 00676 00677 it.IterationHandle = intptr_t(FindHandle.take()); 00678 SmallString<128> directory_entry_path(path); 00679 path::append(directory_entry_path, directory_entry_name_utf8.str()); 00680 it.CurrentEntry = directory_entry(directory_entry_path.str()); 00681 00682 return std::error_code(); 00683 } 00684 00685 std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) { 00686 if (it.IterationHandle != 0) 00687 // Closes the handle if it's valid. 00688 ScopedFindHandle close(HANDLE(it.IterationHandle)); 00689 it.IterationHandle = 0; 00690 it.CurrentEntry = directory_entry(); 00691 return std::error_code(); 00692 } 00693 00694 std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { 00695 WIN32_FIND_DATAW FindData; 00696 if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { 00697 DWORD LastError = ::GetLastError(); 00698 // Check for end. 00699 if (LastError == ERROR_NO_MORE_FILES) 00700 return detail::directory_iterator_destruct(it); 00701 return windows_error(LastError); 00702 } 00703 00704 size_t FilenameLen = ::wcslen(FindData.cFileName); 00705 if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || 00706 (FilenameLen == 2 && FindData.cFileName[0] == L'.' && 00707 FindData.cFileName[1] == L'.')) 00708 return directory_iterator_increment(it); 00709 00710 SmallString<128> directory_entry_path_utf8; 00711 if (std::error_code ec = 00712 UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), 00713 directory_entry_path_utf8)) 00714 return ec; 00715 00716 it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); 00717 return std::error_code(); 00718 } 00719 00720 std::error_code openFileForRead(const Twine &Name, int &ResultFD) { 00721 SmallString<128> PathStorage; 00722 SmallVector<wchar_t, 128> PathUTF16; 00723 00724 if (std::error_code EC = 00725 UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16)) 00726 return EC; 00727 00728 HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ, 00729 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 00730 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 00731 if (H == INVALID_HANDLE_VALUE) { 00732 DWORD LastError = ::GetLastError(); 00733 std::error_code EC = windows_error(LastError); 00734 // Provide a better error message when trying to open directories. 00735 // This only runs if we failed to open the file, so there is probably 00736 // no performances issues. 00737 if (LastError != ERROR_ACCESS_DENIED) 00738 return EC; 00739 if (is_directory(Name)) 00740 return make_error_code(errc::is_a_directory); 00741 return EC; 00742 } 00743 00744 int FD = ::_open_osfhandle(intptr_t(H), 0); 00745 if (FD == -1) { 00746 ::CloseHandle(H); 00747 return windows_error(ERROR_INVALID_HANDLE); 00748 } 00749 00750 ResultFD = FD; 00751 return std::error_code(); 00752 } 00753 00754 std::error_code openFileForWrite(const Twine &Name, int &ResultFD, 00755 sys::fs::OpenFlags Flags, unsigned Mode) { 00756 // Verify that we don't have both "append" and "excl". 00757 assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && 00758 "Cannot specify both 'excl' and 'append' file creation flags!"); 00759 00760 SmallString<128> PathStorage; 00761 SmallVector<wchar_t, 128> PathUTF16; 00762 00763 if (std::error_code EC = 00764 UTF8ToUTF16(Name.toStringRef(PathStorage), PathUTF16)) 00765 return EC; 00766 00767 DWORD CreationDisposition; 00768 if (Flags & F_Excl) 00769 CreationDisposition = CREATE_NEW; 00770 else if (Flags & F_Append) 00771 CreationDisposition = OPEN_ALWAYS; 00772 else 00773 CreationDisposition = CREATE_ALWAYS; 00774 00775 DWORD Access = GENERIC_WRITE; 00776 if (Flags & F_RW) 00777 Access |= GENERIC_READ; 00778 00779 HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, 00780 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 00781 CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); 00782 00783 if (H == INVALID_HANDLE_VALUE) { 00784 DWORD LastError = ::GetLastError(); 00785 std::error_code EC = windows_error(LastError); 00786 // Provide a better error message when trying to open directories. 00787 // This only runs if we failed to open the file, so there is probably 00788 // no performances issues. 00789 if (LastError != ERROR_ACCESS_DENIED) 00790 return EC; 00791 if (is_directory(Name)) 00792 return make_error_code(errc::is_a_directory); 00793 return EC; 00794 } 00795 00796 int OpenFlags = 0; 00797 if (Flags & F_Append) 00798 OpenFlags |= _O_APPEND; 00799 00800 if (Flags & F_Text) 00801 OpenFlags |= _O_TEXT; 00802 00803 int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); 00804 if (FD == -1) { 00805 ::CloseHandle(H); 00806 return windows_error(ERROR_INVALID_HANDLE); 00807 } 00808 00809 ResultFD = FD; 00810 return std::error_code(); 00811 } 00812 } // end namespace fs 00813 00814 namespace path { 00815 00816 bool home_directory(SmallVectorImpl<char> &result) { 00817 wchar_t Path[MAX_PATH]; 00818 if (::SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, 00819 /*SHGFP_TYPE_CURRENT*/0, Path) != S_OK) 00820 return false; 00821 00822 if (UTF16ToUTF8(Path, ::wcslen(Path), result)) 00823 return false; 00824 00825 return true; 00826 } 00827 00828 static bool getTempDirEnvVar(const char *Var, SmallVectorImpl<char> &Res) { 00829 SmallVector<wchar_t, 128> NameUTF16; 00830 if (windows::UTF8ToUTF16(Var, NameUTF16)) 00831 return false; 00832 00833 SmallVector<wchar_t, 1024> Buf; 00834 size_t Size = 1024; 00835 do { 00836 Buf.reserve(Size); 00837 Size = 00838 GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); 00839 if (Size == 0) 00840 return false; 00841 00842 // Try again with larger buffer. 00843 } while (Size > Buf.capacity()); 00844 Buf.set_size(Size); 00845 00846 if (windows::UTF16ToUTF8(Buf.data(), Size, Res)) 00847 return false; 00848 return true; 00849 } 00850 00851 static bool getTempDirEnvVar(SmallVectorImpl<char> &Res) { 00852 const char *EnvironmentVariables[] = {"TMP", "TEMP", "USERPROFILE"}; 00853 for (const char *Env : EnvironmentVariables) { 00854 if (getTempDirEnvVar(Env, Res)) 00855 return true; 00856 } 00857 return false; 00858 } 00859 00860 void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl<char> &Result) { 00861 (void)ErasedOnReboot; 00862 Result.clear(); 00863 00864 // Check whether the temporary directory is specified by an environment 00865 // variable. 00866 if (getTempDirEnvVar(Result)) 00867 return; 00868 00869 // Fall back to a system default. 00870 const char *DefaultResult = "C:\\TEMP"; 00871 Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); 00872 } 00873 } // end namespace path 00874 00875 namespace windows { 00876 std::error_code UTF8ToUTF16(llvm::StringRef utf8, 00877 llvm::SmallVectorImpl<wchar_t> &utf16) { 00878 if (!utf8.empty()) { 00879 int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), 00880 utf8.size(), utf16.begin(), 0); 00881 00882 if (len == 0) 00883 return windows_error(::GetLastError()); 00884 00885 utf16.reserve(len + 1); 00886 utf16.set_size(len); 00887 00888 len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), 00889 utf8.size(), utf16.begin(), utf16.size()); 00890 00891 if (len == 0) 00892 return windows_error(::GetLastError()); 00893 } 00894 00895 // Make utf16 null terminated. 00896 utf16.push_back(0); 00897 utf16.pop_back(); 00898 00899 return std::error_code(); 00900 } 00901 00902 static 00903 std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, 00904 size_t utf16_len, 00905 llvm::SmallVectorImpl<char> &utf8) { 00906 if (utf16_len) { 00907 // Get length. 00908 int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(), 00909 0, NULL, NULL); 00910 00911 if (len == 0) 00912 return windows_error(::GetLastError()); 00913 00914 utf8.reserve(len); 00915 utf8.set_size(len); 00916 00917 // Now do the actual conversion. 00918 len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(), 00919 utf8.size(), NULL, NULL); 00920 00921 if (len == 0) 00922 return windows_error(::GetLastError()); 00923 } 00924 00925 // Make utf8 null terminated. 00926 utf8.push_back(0); 00927 utf8.pop_back(); 00928 00929 return std::error_code(); 00930 } 00931 00932 std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, 00933 llvm::SmallVectorImpl<char> &utf8) { 00934 return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8); 00935 } 00936 00937 std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, 00938 llvm::SmallVectorImpl<char> &utf8) { 00939 return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8); 00940 } 00941 } // end namespace windows 00942 } // end namespace sys 00943 } // end namespace llvm