X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FSupport%2FWindows%2FPath.inc;h=fb484778e65226125a23e9a0674b2c43b8fd1907;hp=94a501b39ac782a711b850a83b5d55482e288c82;hb=7acd886ecfa0adc8a14476eafe8cf1fa981cfe18;hpb=f42d4247ae1138c6deed50f92dcd1a4f34e07dec diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index 94a501b39ac..fb484778e65 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -17,12 +17,17 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" -#include "Windows.h" +#include "llvm/Support/WindowsError.h" #include #include #include #include +// These two headers must be included last, and make sure shlobj is required +// after Windows.h to make sure it picks up our definition of _WIN32_WINNT +#include "WindowsSupport.h" +#include + #undef max // MinGW doesn't define this. @@ -40,175 +45,35 @@ using namespace llvm; using llvm::sys::windows::UTF8ToUTF16; using llvm::sys::windows::UTF16ToUTF8; -namespace { - typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)( - /*__in*/ LPCWSTR lpSymlinkFileName, - /*__in*/ LPCWSTR lpTargetFileName, - /*__in*/ DWORD dwFlags); - - PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW( - ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), - "CreateSymbolicLinkW")); - - error_code TempDir(SmallVectorImpl &result) { - retry_temp_dir: - DWORD len = ::GetTempPathW(result.capacity(), result.begin()); - - if (len == 0) - return windows_error(::GetLastError()); - - if (len > result.capacity()) { - result.reserve(len); - goto retry_temp_dir; - } - - result.set_size(len); - return error_code::success(); - } - - bool is_separator(const wchar_t value) { - switch (value) { - case L'\\': - case L'/': - return true; - default: - return false; - } - } +static error_code windows_error(DWORD E) { + return mapWindowsError(E); } -// FIXME: mode should be used here and default to user r/w only, -// it currently comes in as a UNIX mode. -static error_code createUniqueEntity(const Twine &model, int &result_fd, - SmallVectorImpl &result_path, - bool makeAbsolute, unsigned mode, - FSEntity Type) { - // Use result_path as temp storage. - result_path.set_size(0); - StringRef m = model.toStringRef(result_path); - - SmallVector model_utf16; - if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec; - - if (makeAbsolute) { - // Make model absolute by prepending a temp directory if it's not already. - bool absolute = sys::path::is_absolute(m); - - if (!absolute) { - SmallVector temp_dir; - if (error_code ec = TempDir(temp_dir)) return ec; - // Handle c: by removing it. - if (model_utf16.size() > 2 && model_utf16[1] == L':') { - model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2); - } - model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end()); - } - } +static error_code TempDir(SmallVectorImpl &Result) { + SmallVector Res; +retry_temp_dir: + DWORD Len = ::GetTempPathW(Res.capacity(), Res.begin()); - // Replace '%' with random chars. From here on, DO NOT modify model. It may be - // needed if the randomly chosen path already exists. - SmallVector random_path_utf16; - - // Get a Crypto Provider for CryptGenRandom. - HCRYPTPROV HCPC; - if (!::CryptAcquireContextW(&HCPC, - NULL, - NULL, - PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT)) + if (Len == 0) return windows_error(::GetLastError()); - ScopedCryptContext CryptoProvider(HCPC); - -retry_random_path: - random_path_utf16.set_size(0); - for (SmallVectorImpl::const_iterator i = model_utf16.begin(), - e = model_utf16.end(); - i != e; ++i) { - if (*i == L'%') { - BYTE val = 0; - if (!::CryptGenRandom(CryptoProvider, 1, &val)) - return windows_error(::GetLastError()); - random_path_utf16.push_back("0123456789abcdef"[val & 15]); - } - else - random_path_utf16.push_back(*i); - } - // Make random_path_utf16 null terminated. - random_path_utf16.push_back(0); - random_path_utf16.pop_back(); - - HANDLE TempFileHandle = INVALID_HANDLE_VALUE; - - switch (Type) { - case FS_File: { - // Try to create + open the path. - TempFileHandle = - ::CreateFileW(random_path_utf16.begin(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, NULL, - // Return ERROR_FILE_EXISTS if the file - // already exists. - CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL); - if (TempFileHandle == INVALID_HANDLE_VALUE) { - // If the file existed, try again, otherwise, error. - error_code ec = windows_error(::GetLastError()); - if (ec == windows_error::file_exists) - goto retry_random_path; - - return ec; - } - // Convert the Windows API file handle into a C-runtime handle. - int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0); - if (fd == -1) { - ::CloseHandle(TempFileHandle); - ::DeleteFileW(random_path_utf16.begin()); - // MSDN doesn't say anything about _open_osfhandle setting errno or - // GetLastError(), so just return invalid_handle. - return windows_error::invalid_handle; - } - - result_fd = fd; - break; - } - - case FS_Name: { - DWORD attributes = ::GetFileAttributesW(random_path_utf16.begin()); - if (attributes != INVALID_FILE_ATTRIBUTES) - goto retry_random_path; - error_code EC = make_error_code(windows_error(::GetLastError())); - if (EC != windows_error::file_not_found && - EC != windows_error::path_not_found) - return EC; - break; + if (Len > Res.capacity()) { + Res.reserve(Len); + goto retry_temp_dir; } - case FS_Dir: - if (!::CreateDirectoryW(random_path_utf16.begin(), NULL)) { - error_code EC = windows_error(::GetLastError()); - if (EC != windows_error::already_exists) - return EC; - goto retry_random_path; - } - break; - } + Res.set_size(Len); + return UTF16ToUTF8(Res.begin(), Res.size(), Result); +} - // Set result_path to the utf-8 representation of the path. - if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), - random_path_utf16.size(), result_path)) { - switch (Type) { - case FS_File: - ::CloseHandle(TempFileHandle); - ::DeleteFileW(random_path_utf16.begin()); - case FS_Name: - break; - case FS_Dir: - ::RemoveDirectoryW(random_path_utf16.begin()); - break; - } - return ec; +static bool is_separator(const wchar_t value) { + switch (value) { + case L'\\': + case L'/': + return true; + default: + return false; } - - return error_code::success(); } namespace llvm { @@ -216,9 +81,28 @@ namespace sys { namespace fs { std::string getMainExecutable(const char *argv0, void *MainExecAddr) { - char pathname[MAX_PATH]; - DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH); - return ret != MAX_PATH ? pathname : ""; + SmallVector PathName; + DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); + + // A zero return value indicates a failure other than insufficient space. + if (Size == 0) + return ""; + + // Insufficient space is determined by a return value equal to the size of + // the buffer passed in. + if (Size == PathName.capacity()) + return ""; + + // On success, GetModuleFileNameW returns the number of characters written to + // the buffer not including the NULL terminator. + PathName.set_size(Size); + + // Convert the result from UTF-16 to UTF-8. + SmallVector PathNameUTF8; + if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) + return ""; + + return std::string(PathNameUTF8.data()); } UniqueID file_status::getUniqueID() const { @@ -241,27 +125,28 @@ TimeValue file_status::getLastModificationTime() const { } error_code current_path(SmallVectorImpl &result) { - SmallVector cur_path; - cur_path.reserve(128); -retry_cur_dir: - DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); - - // A zero return value indicates a failure other than insufficient space. - if (len == 0) - return windows_error(::GetLastError()); + SmallVector cur_path; + DWORD len = MAX_PATH; - // If there's insufficient space, the len returned is larger than the len - // given. - if (len > cur_path.capacity()) { + do { cur_path.reserve(len); - goto retry_cur_dir; - } + len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); + + // A zero return value indicates a failure other than insufficient space. + if (len == 0) + return windows_error(::GetLastError()); + // If there's insufficient space, the len returned is larger than the len + // given. + } while (len > cur_path.capacity()); + + // On success, GetCurrentDirectoryW returns the number of characters not + // including the null-terminator. cur_path.set_size(len); return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } -error_code create_directory(const Twine &path, bool &existed) { +error_code create_directory(const Twine &path, bool IgnoreExisting) { SmallString<128> path_storage; SmallVector path_utf16; @@ -270,41 +155,21 @@ error_code create_directory(const Twine &path, bool &existed) { return ec; if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { - error_code ec = windows_error(::GetLastError()); - if (ec == windows_error::already_exists) - existed = true; - else - return ec; - } else - existed = false; + DWORD LastError = ::GetLastError(); + if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) + return windows_error(LastError); + } - return error_code::success(); + return error_code(); } -error_code create_hard_link(const Twine &to, const Twine &from) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toStringRef(from_storage); - StringRef t = to.toStringRef(to_storage); - - // Convert to utf-16. - SmallVector wide_from; - SmallVector wide_to; - if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; - if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; - - if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) - return windows_error(::GetLastError()); - - return error_code::success(); +error_code normalize_separators(SmallVectorImpl &Path) { + (void) Path; + return error_code(); } -error_code create_symlink(const Twine &to, const Twine &from) { - // Only do it if the function is available at runtime. - if (!create_symbolic_link_api) - return make_error_code(errc::function_not_supported); - +// We can't use symbolic links for windows. +error_code create_link(const Twine &to, const Twine &from) { // Get arguments. SmallString<128> from_storage; SmallString<128> to_storage; @@ -317,50 +182,41 @@ error_code create_symlink(const Twine &to, const Twine &from) { if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; - if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0)) + if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) return windows_error(::GetLastError()); - return error_code::success(); + return error_code(); } -error_code remove(const Twine &path, bool &existed) { +error_code remove(const Twine &path, bool IgnoreNonExisting) { SmallString<128> path_storage; SmallVector path_utf16; - file_status st; - error_code EC = status(path, st); - if (EC) { - if (EC == windows_error::file_not_found || - EC == windows_error::path_not_found) { - existed = false; - return error_code::success(); - } - return EC; + file_status ST; + if (error_code EC = status(path, ST)) { + if (EC != std::errc::no_such_file_or_directory || !IgnoreNonExisting) + return EC; + return error_code(); } if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) return ec; - if (st.type() == file_type::directory_file) { + if (ST.type() == file_type::directory_file) { if (!::RemoveDirectoryW(c_str(path_utf16))) { - error_code ec = windows_error(::GetLastError()); - if (ec != windows_error::file_not_found) - return ec; - existed = false; - } else - existed = true; - } else { - if (!::DeleteFileW(c_str(path_utf16))) { - error_code ec = windows_error(::GetLastError()); - if (ec != windows_error::file_not_found) - return ec; - existed = false; - } else - existed = true; + error_code EC = windows_error(::GetLastError()); + if (EC != std::errc::no_such_file_or_directory || !IgnoreNonExisting) + return EC; + } + return error_code(); } - - return error_code::success(); + if (!::DeleteFileW(c_str(path_utf16))) { + error_code EC = windows_error(::GetLastError()); + if (EC != std::errc::no_such_file_or_directory || !IgnoreNonExisting) + return EC; + } + return error_code(); } error_code rename(const Twine &from, const Twine &to) { @@ -376,13 +232,13 @@ error_code rename(const Twine &from, const Twine &to) { if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; - error_code ec = error_code::success(); + error_code ec = error_code(); for (int i = 0; i < 2000; i++) { if (::MoveFileExW(wide_from.begin(), wide_to.begin(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) - return error_code::success(); - ec = windows_error(::GetLastError()); - if (ec != windows_error::access_denied) + return error_code(); + DWORD LastError = ::GetLastError(); + if (LastError != ERROR_ACCESS_DENIED) break; // Retry MoveFile() at ACCESS_DENIED. // System scanners (eg. indexer) might open the source file when @@ -425,14 +281,14 @@ error_code exists(const Twine &path, bool &result) { if (attributes == INVALID_FILE_ATTRIBUTES) { // See if the file didn't actually exist. - error_code ec = make_error_code(windows_error(::GetLastError())); - if (ec != windows_error::file_not_found && - ec != windows_error::path_not_found) - return ec; + DWORD LastError = ::GetLastError(); + if (LastError != ERROR_FILE_NOT_FOUND && + LastError != ERROR_PATH_NOT_FOUND) + return windows_error(LastError); result = false; } else result = true; - return error_code::success(); + return error_code(); } bool can_write(const Twine &Path) { @@ -474,7 +330,7 @@ error_code equivalent(const Twine &A, const Twine &B, bool &result) { if (error_code ec = status(A, fsA)) return ec; if (error_code ec = status(B, fsB)) return ec; result = equivalent(fsA, fsB); - return error_code::success(); + return error_code(); } static bool isReservedName(StringRef path) { @@ -512,16 +368,16 @@ static error_code getStatus(HANDLE FileHandle, file_status &Result) { if (Err != NO_ERROR) return windows_error(Err); Result = file_status(file_type::type_unknown); - return error_code::success(); + return error_code(); } case FILE_TYPE_DISK: break; case FILE_TYPE_CHAR: Result = file_status(file_type::character_file); - return error_code::success(); + return error_code(); case FILE_TYPE_PIPE: Result = file_status(file_type::fifo_file); - return error_code::success(); + return error_code(); } BY_HANDLE_FILE_INFORMATION Info; @@ -537,19 +393,19 @@ static error_code getStatus(HANDLE FileHandle, file_status &Result) { Info.ftLastWriteTime.dwLowDateTime, Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); - return error_code::success(); + return error_code(); } handle_status_error: - error_code EC = windows_error(::GetLastError()); - if (EC == windows_error::file_not_found || - EC == windows_error::path_not_found) + DWORD LastError = ::GetLastError(); + if (LastError == ERROR_FILE_NOT_FOUND || + LastError == ERROR_PATH_NOT_FOUND) Result = file_status(file_type::file_not_found); - else if (EC == windows_error::sharing_violation) + else if (LastError == ERROR_SHARING_VIOLATION) Result = file_status(file_type::type_unknown); else Result = file_status(file_type::status_error); - return EC; + return windows_error(LastError); } error_code status(const Twine &path, file_status &result) { @@ -559,7 +415,7 @@ error_code status(const Twine &path, file_status &result) { StringRef path8 = path.toStringRef(path_storage); if (isReservedName(path8)) { result = file_status(file_type::character_file); - return error_code::success(); + return error_code(); } if (error_code ec = UTF8ToUTF16(path8, path_utf16)) @@ -607,7 +463,7 @@ error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { HANDLE FileHandle = reinterpret_cast(_get_osfhandle(FD)); if (!SetFileTime(FileHandle, NULL, &FT, &FT)) return windows_error(::GetLastError()); - return error_code::success(); + return error_code(); } error_code get_magic(const Twine &path, uint32_t len, @@ -649,7 +505,7 @@ error_code get_magic(const Twine &path, uint32_t len, } result.set_size(len); - return error_code::success(); + return error_code(); } error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { @@ -661,7 +517,7 @@ error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { _close(FileDescriptor); } else ::CloseHandle(FileHandle); - return make_error_code(errc::invalid_argument); + return make_error_code(std::errc::invalid_argument); } DWORD flprotect; @@ -671,12 +527,11 @@ error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { case priv: flprotect = PAGE_WRITECOPY; break; } - FileMappingHandle = ::CreateFileMapping(FileHandle, - 0, - flprotect, - (Offset + Size) >> 32, - (Offset + Size) & 0xffffffff, - 0); + FileMappingHandle = + ::CreateFileMappingW(FileHandle, 0, flprotect, + (Offset + Size) >> 32, + (Offset + Size) & 0xffffffff, + 0); if (FileMappingHandle == NULL) { error_code ec = windows_error(GetLastError()); if (FileDescriptor) { @@ -734,7 +589,7 @@ error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { _close(FileDescriptor); // Also closes FileHandle. } else ::CloseHandle(FileHandle); - return error_code::success(); + return error_code(); } mapped_file_region::mapped_file_region(const Twine &path, @@ -798,7 +653,7 @@ mapped_file_region::mapped_file_region(int fd, if (closefd) _close(FileDescriptor); FileDescriptor = 0; - ec = make_error_code(errc::bad_file_descriptor); + ec = make_error_code(std::errc::bad_file_descriptor); return; } @@ -815,7 +670,6 @@ mapped_file_region::~mapped_file_region() { ::UnmapViewOfFile(Mapping); } -#if LLVM_HAS_RVALUE_REFERENCES mapped_file_region::mapped_file_region(mapped_file_region &&other) : Mode(other.Mode) , Size(other.Size) @@ -827,7 +681,6 @@ mapped_file_region::mapped_file_region(mapped_file_region &&other) other.FileHandle = INVALID_HANDLE_VALUE; other.FileDescriptor = 0; } -#endif mapped_file_region::mapmode mapped_file_region::flags() const { assert(Mapping && "Mapping failed but used anyway!"); @@ -840,7 +693,7 @@ uint64_t mapped_file_region::size() const { } char *mapped_file_region::data() const { - assert(Mode != readonly && "Cannot get non const data for readonly mapping!"); + assert(Mode != readonly && "Cannot get non-const data for readonly mapping!"); assert(Mapping && "Mapping failed but used anyway!"); return reinterpret_cast(Mapping); } @@ -885,11 +738,11 @@ error_code detail::directory_iterator_construct(detail::DirIterState &it, (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && FirstFind.cFileName[1] == L'.')) if (!::FindNextFileW(FindHandle, &FirstFind)) { - error_code ec = windows_error(::GetLastError()); + DWORD LastError = ::GetLastError(); // Check for end. - if (ec == windows_error::no_more_files) + if (LastError == ERROR_NO_MORE_FILES) return detail::directory_iterator_destruct(it); - return ec; + return windows_error(LastError); } else FilenameLen = ::wcslen(FirstFind.cFileName); @@ -905,7 +758,7 @@ error_code detail::directory_iterator_construct(detail::DirIterState &it, path::append(directory_entry_path, directory_entry_name_utf8.str()); it.CurrentEntry = directory_entry(directory_entry_path.str()); - return error_code::success(); + return error_code(); } error_code detail::directory_iterator_destruct(detail::DirIterState &it) { @@ -914,17 +767,17 @@ error_code detail::directory_iterator_destruct(detail::DirIterState &it) { ScopedFindHandle close(HANDLE(it.IterationHandle)); it.IterationHandle = 0; it.CurrentEntry = directory_entry(); - return error_code::success(); + return error_code(); } error_code detail::directory_iterator_increment(detail::DirIterState &it) { WIN32_FIND_DATAW FindData; if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { - error_code ec = windows_error(::GetLastError()); + DWORD LastError = ::GetLastError(); // Check for end. - if (ec == windows_error::no_more_files) + if (LastError == ERROR_NO_MORE_FILES) return detail::directory_iterator_destruct(it); - return ec; + return windows_error(LastError); } size_t FilenameLen = ::wcslen(FindData.cFileName); @@ -940,18 +793,7 @@ error_code detail::directory_iterator_increment(detail::DirIterState &it) { return ec; it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); - return error_code::success(); -} - -error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, - bool map_writable, void *&result) { - assert(0 && "NOT IMPLEMENTED"); - return windows_error::invalid_function; -} - -error_code unmap_file_pages(void *base, size_t size) { - assert(0 && "NOT IMPLEMENTED"); - return windows_error::invalid_function; + return error_code(); } error_code openFileForRead(const Twine &Name, int &ResultFD) { @@ -966,25 +808,26 @@ error_code openFileForRead(const Twine &Name, int &ResultFD) { FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (H == INVALID_HANDLE_VALUE) { - error_code EC = windows_error(::GetLastError()); + DWORD LastError = ::GetLastError(); + error_code EC = windows_error(LastError); // Provide a better error message when trying to open directories. // This only runs if we failed to open the file, so there is probably // no performances issues. - if (EC != windows_error::access_denied) + if (LastError != ERROR_ACCESS_DENIED) return EC; if (is_directory(Name)) - return error_code(errc::is_a_directory, posix_category()); + return make_error_code(std::errc::is_a_directory); return EC; } int FD = ::_open_osfhandle(intptr_t(H), 0); if (FD == -1) { ::CloseHandle(H); - return windows_error::invalid_handle; + return windows_error(ERROR_INVALID_HANDLE); } ResultFD = FD; - return error_code::success(); + return error_code(); } error_code openFileForWrite(const Twine &Name, int &ResultFD, @@ -1008,19 +851,24 @@ error_code openFileForWrite(const Twine &Name, int &ResultFD, else CreationDisposition = CREATE_ALWAYS; - HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_WRITE, + DWORD Access = GENERIC_WRITE; + if (Flags & F_RW) + Access |= GENERIC_READ; + + HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); if (H == INVALID_HANDLE_VALUE) { - error_code EC = windows_error(::GetLastError()); + DWORD LastError = ::GetLastError(); + error_code EC = windows_error(LastError); // Provide a better error message when trying to open directories. // This only runs if we failed to open the file, so there is probably // no performances issues. - if (EC != windows_error::access_denied) + if (LastError != ERROR_ACCESS_DENIED) return EC; if (is_directory(Name)) - return error_code(errc::is_a_directory, posix_category()); + return make_error_code(std::errc::is_a_directory); return EC; } @@ -1028,75 +876,89 @@ error_code openFileForWrite(const Twine &Name, int &ResultFD, if (Flags & F_Append) OpenFlags |= _O_APPEND; - if (!(Flags & F_Binary)) + if (Flags & F_Text) OpenFlags |= _O_TEXT; int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); if (FD == -1) { ::CloseHandle(H); - return windows_error::invalid_handle; + return windows_error(ERROR_INVALID_HANDLE); } ResultFD = FD; - return error_code::success(); + return error_code(); } } // end namespace fs +namespace path { + +bool home_directory(SmallVectorImpl &result) { + wchar_t Path[MAX_PATH]; + if (::SHGetFolderPathW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, 0, + /*SHGFP_TYPE_CURRENT*/0, Path) != S_OK) + return false; + + if (UTF16ToUTF8(Path, ::wcslen(Path), result)) + return false; + + return true; +} + +} // end namespace path + namespace windows { llvm::error_code UTF8ToUTF16(llvm::StringRef utf8, llvm::SmallVectorImpl &utf16) { - int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, - utf8.begin(), utf8.size(), - utf16.begin(), 0); + if (!utf8.empty()) { + int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), + utf8.size(), utf16.begin(), 0); - if (len == 0) - return llvm::windows_error(::GetLastError()); + if (len == 0) + return windows_error(::GetLastError()); - utf16.reserve(len + 1); - utf16.set_size(len); + utf16.reserve(len + 1); + utf16.set_size(len); - len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, - utf8.begin(), utf8.size(), - utf16.begin(), utf16.size()); + len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), + utf8.size(), utf16.begin(), utf16.size()); - if (len == 0) - return llvm::windows_error(::GetLastError()); + if (len == 0) + return windows_error(::GetLastError()); + } // Make utf16 null terminated. utf16.push_back(0); utf16.pop_back(); - return llvm::error_code::success(); + return llvm::error_code(); } llvm::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, llvm::SmallVectorImpl &utf8) { - // Get length. - int len = ::WideCharToMultiByte(CP_UTF8, 0, - utf16, utf16_len, - utf8.begin(), 0, - NULL, NULL); + if (utf16_len) { + // Get length. + int len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.begin(), + 0, NULL, NULL); - if (len == 0) - return llvm::windows_error(::GetLastError()); + if (len == 0) + return windows_error(::GetLastError()); - utf8.reserve(len); - utf8.set_size(len); + utf8.reserve(len); + utf8.set_size(len); - // Now do the actual conversion. - len = ::WideCharToMultiByte(CP_UTF8, 0, - utf16, utf16_len, - utf8.data(), utf8.size(), - NULL, NULL); + // Now do the actual conversion. + len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.data(), + utf8.size(), NULL, NULL); - if (len == 0) - return llvm::windows_error(::GetLastError()); + if (len == 0) + return windows_error(::GetLastError()); + } // Make utf8 null terminated. utf8.push_back(0); utf8.pop_back(); - return llvm::error_code::success(); + return llvm::error_code(); } } // end namespace windows } // end namespace sys