X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FSupport%2FWindows%2FPath.inc;h=140aadcfe66c0a026d9e9256e24ad1ce8480a999;hp=c39600357be3a7a898016a68024462d7db331af4;hb=038e20451d144ddb117a0dfe8ff220c8b26f4a7a;hpb=bbf1c8d24c8c5ec1aa96623457911b97fcd5f3c6 diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index c39600357be..140aadcfe66 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -17,6 +17,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/WindowsError.h" #include #include #include @@ -44,21 +45,8 @@ using namespace llvm; using llvm::sys::windows::UTF8ToUTF16; using llvm::sys::windows::UTF16ToUTF8; -static error_code TempDir(SmallVectorImpl &Result) { - SmallVector Res; -retry_temp_dir: - DWORD Len = ::GetTempPathW(Res.capacity(), Res.begin()); - - if (Len == 0) - return windows_error(::GetLastError()); - - if (Len > Res.capacity()) { - Res.reserve(Len); - goto retry_temp_dir; - } - - Res.set_size(Len); - return UTF16ToUTF8(Res.begin(), Res.size(), Result); +static std::error_code windows_error(DWORD E) { + return mapWindowsError(E); } static bool is_separator(const wchar_t value) { @@ -71,6 +59,59 @@ static bool is_separator(const wchar_t value) { } } +// Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the +// path is longer than CreateDirectory can tolerate, make it absolute and +// prefixed by '\\?\'. +static std::error_code widenPath(const Twine &Path8, + SmallVectorImpl &Path16) { + const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename. + + // Several operations would convert Path8 to SmallString; more efficient to + // do it once up front. + SmallString<128> Path8Str; + Path8.toVector(Path8Str); + + // If we made this path absolute, how much longer would it get? + size_t CurPathLen; + if (llvm::sys::path::is_absolute(Twine(Path8Str))) + CurPathLen = 0; // No contribution from current_path needed. + else { + CurPathLen = ::GetCurrentDirectoryW(0, NULL); + if (CurPathLen == 0) + return windows_error(::GetLastError()); + } + + // Would the absolute path be longer than our limit? + if ((Path8Str.size() + CurPathLen) >= MaxDirLen && + !Path8Str.startswith("\\\\?\\")) { + SmallString<2*MAX_PATH> FullPath("\\\\?\\"); + if (CurPathLen) { + SmallString<80> CurPath; + if (std::error_code EC = llvm::sys::fs::current_path(CurPath)) + return EC; + FullPath.append(CurPath); + } + // Traverse the requested path, canonicalizing . and .. as we go (because + // the \\?\ prefix is documented to treat them as real components). + // The iterators don't report separators and append() always attaches + // preferred_separator so we don't need to call native() on the result. + for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), + E = llvm::sys::path::end(Path8Str); + I != E; ++I) { + if (I->size() == 1 && *I == ".") + continue; + if (I->size() == 2 && *I == "..") + llvm::sys::path::remove_filename(FullPath); + else + llvm::sys::path::append(FullPath, *I); + } + return UTF8ToUTF16(FullPath, Path16); + } + + // Just use the caller's original path. + return UTF8ToUTF16(Path8Str, Path16); +} + namespace llvm { namespace sys { namespace fs { @@ -119,7 +160,7 @@ TimeValue file_status::getLastModificationTime() const { return Ret; } -error_code current_path(SmallVectorImpl &result) { +std::error_code current_path(SmallVectorImpl &result) { SmallVector cur_path; DWORD len = MAX_PATH; @@ -141,93 +182,82 @@ error_code current_path(SmallVectorImpl &result) { return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } -error_code create_directory(const Twine &path, bool IgnoreExisting) { - SmallString<128> path_storage; +std::error_code create_directory(const Twine &path, bool IgnoreExisting) { SmallVector path_utf16; - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) + if (std::error_code ec = widenPath(path, path_utf16)) return ec; if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { - error_code ec = windows_error(::GetLastError()); - if (ec != windows_error::already_exists || !IgnoreExisting) - return ec; + DWORD LastError = ::GetLastError(); + if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) + return windows_error(LastError); } - return error_code::success(); + return std::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); - +// We can't use symbolic links for windows. +std::error_code create_link(const Twine &to, const Twine &from) { // 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 (std::error_code ec = widenPath(from, wide_from)) + return ec; + if (std::error_code ec = widenPath(to, wide_to)) + return ec; if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) return windows_error(::GetLastError()); - return error_code::success(); + return std::error_code(); } -error_code remove(const Twine &path, bool IgnoreNonExisting) { - SmallString<128> path_storage; +std::error_code remove(const Twine &path, bool IgnoreNonExisting) { SmallVector path_utf16; file_status ST; - if (error_code EC = status(path, ST)) { + if (std::error_code EC = status(path, ST)) { if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) return EC; - return error_code::success(); + return std::error_code(); } - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) + if (std::error_code ec = widenPath(path, path_utf16)) return ec; if (ST.type() == file_type::directory_file) { if (!::RemoveDirectoryW(c_str(path_utf16))) { - error_code EC = windows_error(::GetLastError()); + std::error_code EC = windows_error(::GetLastError()); if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) return EC; } - return error_code::success(); + return std::error_code(); } if (!::DeleteFileW(c_str(path_utf16))) { - error_code EC = windows_error(::GetLastError()); + std::error_code EC = windows_error(::GetLastError()); if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) return EC; } - return error_code::success(); + return std::error_code(); } -error_code rename(const Twine &from, const Twine &to) { - // Get arguments. - SmallString<128> from_storage; - SmallString<128> to_storage; - StringRef f = from.toStringRef(from_storage); - StringRef t = to.toStringRef(to_storage); - +std::error_code rename(const Twine &from, const Twine &to) { // 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 (std::error_code ec = widenPath(from, wide_from)) + return ec; + if (std::error_code ec = widenPath(to, wide_to)) + return ec; - error_code ec = error_code::success(); + std::error_code ec = std::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 std::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 @@ -238,69 +268,45 @@ error_code rename(const Twine &from, const Twine &to) { return ec; } -error_code resize_file(const Twine &path, uint64_t size) { - SmallString<128> path_storage; +std::error_code resize_file(const Twine &path, uint64_t size) { SmallVector path_utf16; - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) + if (std::error_code ec = widenPath(path, path_utf16)) return ec; int fd = ::_wopen(path_utf16.begin(), O_BINARY | _O_RDWR, S_IWRITE); if (fd == -1) - return error_code(errno, generic_category()); + return std::error_code(errno, std::generic_category()); #ifdef HAVE__CHSIZE_S errno_t error = ::_chsize_s(fd, size); #else errno_t error = ::_chsize(fd, size); #endif ::close(fd); - return error_code(error, generic_category()); -} - -error_code exists(const Twine &path, bool &result) { - SmallString<128> path_storage; - SmallVector path_utf16; - - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) - return ec; - - DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); - - 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; - result = false; - } else - result = true; - return error_code::success(); + return std::error_code(error, std::generic_category()); } -bool can_write(const Twine &Path) { - // FIXME: take security attributes into account. - SmallString<128> PathStorage; +std::error_code access(const Twine &Path, AccessMode Mode) { SmallVector PathUtf16; - if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) - return false; + if (std::error_code EC = widenPath(Path, PathUtf16)) + return EC; - DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); - return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY); -} + DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); -bool can_execute(const Twine &Path) { - SmallString<128> PathStorage; - SmallVector PathUtf16; + if (Attributes == INVALID_FILE_ATTRIBUTES) { + // See if the file didn't actually exist. + DWORD LastError = ::GetLastError(); + if (LastError != ERROR_FILE_NOT_FOUND && + LastError != ERROR_PATH_NOT_FOUND) + return windows_error(LastError); + return errc::no_such_file_or_directory; + } - if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16)) - return false; + if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) + return errc::permission_denied; - DWORD Attr = ::GetFileAttributesW(PathUtf16.begin()); - return Attr != INVALID_FILE_ATTRIBUTES; + return std::error_code(); } bool equivalent(file_status A, file_status B) { @@ -314,12 +320,14 @@ bool equivalent(file_status A, file_status B) { A.VolumeSerialNumber == B.VolumeSerialNumber; } -error_code equivalent(const Twine &A, const Twine &B, bool &result) { +std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { file_status fsA, fsB; - if (error_code ec = status(A, fsA)) return ec; - if (error_code ec = status(B, fsB)) return ec; + if (std::error_code ec = status(A, fsA)) + return ec; + if (std::error_code ec = status(B, fsB)) + return ec; result = equivalent(fsA, fsB); - return error_code::success(); + return std::error_code(); } static bool isReservedName(StringRef path) { @@ -345,7 +353,7 @@ static bool isReservedName(StringRef path) { return false; } -static error_code getStatus(HANDLE FileHandle, file_status &Result) { +static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { if (FileHandle == INVALID_HANDLE_VALUE) goto handle_status_error; @@ -357,16 +365,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 std::error_code(); } case FILE_TYPE_DISK: break; case FILE_TYPE_CHAR: Result = file_status(file_type::character_file); - return error_code::success(); + return std::error_code(); case FILE_TYPE_PIPE: Result = file_status(file_type::fifo_file); - return error_code::success(); + return std::error_code(); } BY_HANDLE_FILE_INFORMATION Info; @@ -382,32 +390,32 @@ 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 std::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) { +std::error_code status(const Twine &path, file_status &result) { SmallString<128> path_storage; SmallVector path_utf16; StringRef path8 = path.toStringRef(path_storage); if (isReservedName(path8)) { result = file_status(file_type::character_file); - return error_code::success(); + return std::error_code(); } - if (error_code ec = UTF8ToUTF16(path8, path_utf16)) + if (std::error_code ec = widenPath(path8, path_utf16)) return ec; DWORD attr = ::GetFileAttributesW(path_utf16.begin()); @@ -438,12 +446,12 @@ error_code status(const Twine &path, file_status &result) { return getStatus(h, result); } -error_code status(int FD, file_status &Result) { +std::error_code status(int FD, file_status &Result) { HANDLE FileHandle = reinterpret_cast(_get_osfhandle(FD)); return getStatus(FileHandle, Result); } -error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { +std::error_code setLastModificationAndAccessTime(int FD, TimeValue Time) { ULARGE_INTEGER UI; UI.QuadPart = Time.toWin32Time(); FILETIME FT; @@ -452,52 +460,10 @@ 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 std::error_code(); } -error_code get_magic(const Twine &path, uint32_t len, - SmallVectorImpl &result) { - SmallString<128> path_storage; - SmallVector path_utf16; - result.set_size(0); - - // Convert path to UTF-16. - if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), - path_utf16)) - return ec; - - // Open file. - HANDLE file = ::CreateFileW(c_str(path_utf16), - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_READONLY, - NULL); - if (file == INVALID_HANDLE_VALUE) - return windows_error(::GetLastError()); - - // Allocate buffer. - result.reserve(len); - - // Get magic! - DWORD bytes_read = 0; - BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL); - error_code ec = windows_error(::GetLastError()); - ::CloseHandle(file); - if (!read_success || (bytes_read != len)) { - // Set result size to the number of bytes read if it's valid. - if (bytes_read <= len) - result.set_size(bytes_read); - // ERROR_HANDLE_EOF is mapped to errc::value_too_large. - return ec; - } - - result.set_size(len); - return error_code::success(); -} - -error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { +std::error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { FileDescriptor = FD; // Make sure that the requested size fits within SIZE_T. if (Size > std::numeric_limits::max()) { @@ -522,7 +488,7 @@ error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { (Offset + Size) & 0xffffffff, 0); if (FileMappingHandle == NULL) { - error_code ec = windows_error(GetLastError()); + std::error_code ec = windows_error(GetLastError()); if (FileDescriptor) { if (CloseFD) _close(FileDescriptor); @@ -543,7 +509,7 @@ error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { Offset & 0xffffffff, Size); if (Mapping == NULL) { - error_code ec = windows_error(GetLastError()); + std::error_code ec = windows_error(GetLastError()); ::CloseHandle(FileMappingHandle); if (FileDescriptor) { if (CloseFD) @@ -557,7 +523,7 @@ error_code mapped_file_region::init(int FD, bool CloseFD, uint64_t Offset) { MEMORY_BASIC_INFORMATION mbi; SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); if (Result == 0) { - error_code ec = windows_error(GetLastError()); + std::error_code ec = windows_error(GetLastError()); ::UnmapViewOfFile(Mapping); ::CloseHandle(FileMappingHandle); if (FileDescriptor) { @@ -578,25 +544,24 @@ 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 std::error_code(); } mapped_file_region::mapped_file_region(const Twine &path, mapmode mode, uint64_t length, uint64_t offset, - error_code &ec) + std::error_code &ec) : Mode(mode) , Size(length) , Mapping() , FileDescriptor() , FileHandle(INVALID_HANDLE_VALUE) , FileMappingHandle() { - SmallString<128> path_storage; SmallVector path_utf16; // Convert path to UTF-16. - if ((ec = UTF8ToUTF16(path.toStringRef(path_storage), path_utf16))) + if (ec = widenPath(path, path_utf16)) return; // Get file handle for creating a file mapping. @@ -630,7 +595,7 @@ mapped_file_region::mapped_file_region(int fd, mapmode mode, uint64_t length, uint64_t offset, - error_code &ec) + std::error_code &ec) : Mode(mode) , Size(length) , Mapping() @@ -698,12 +663,11 @@ int mapped_file_region::alignment() { return SysInfo.dwAllocationGranularity; } -error_code detail::directory_iterator_construct(detail::DirIterState &it, +std::error_code detail::directory_iterator_construct(detail::DirIterState &it, StringRef path){ SmallVector path_utf16; - if (error_code ec = UTF8ToUTF16(path, - path_utf16)) + if (std::error_code ec = widenPath(path, path_utf16)) return ec; // Convert path to the format that Windows is happy with. @@ -727,19 +691,19 @@ 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); // Construct the current directory entry. SmallString<128> directory_entry_name_utf8; - if (error_code ec = UTF16ToUTF8(FirstFind.cFileName, - ::wcslen(FirstFind.cFileName), - directory_entry_name_utf8)) + if (std::error_code ec = + UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), + directory_entry_name_utf8)) return ec; it.IterationHandle = intptr_t(FindHandle.take()); @@ -747,26 +711,26 @@ 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 std::error_code(); } -error_code detail::directory_iterator_destruct(detail::DirIterState &it) { +std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) { if (it.IterationHandle != 0) // Closes the handle if it's valid. ScopedFindHandle close(HANDLE(it.IterationHandle)); it.IterationHandle = 0; it.CurrentEntry = directory_entry(); - return error_code::success(); + return std::error_code(); } -error_code detail::directory_iterator_increment(detail::DirIterState &it) { +std::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); @@ -776,70 +740,56 @@ error_code detail::directory_iterator_increment(detail::DirIterState &it) { return directory_iterator_increment(it); SmallString<128> directory_entry_path_utf8; - if (error_code ec = UTF16ToUTF8(FindData.cFileName, - ::wcslen(FindData.cFileName), - directory_entry_path_utf8)) + if (std::error_code ec = + UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), + directory_entry_path_utf8)) 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; + return std::error_code(); } -error_code unmap_file_pages(void *base, size_t size) { - assert(0 && "NOT IMPLEMENTED"); - return windows_error::invalid_function; -} - -error_code openFileForRead(const Twine &Name, int &ResultFD) { - SmallString<128> PathStorage; +std::error_code openFileForRead(const Twine &Name, int &ResultFD) { SmallVector PathUTF16; - if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage), - PathUTF16)) + if (std::error_code EC = widenPath(Name, PathUTF16)) return EC; HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_READ, 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(); + std::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(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 std::error_code(); } -error_code openFileForWrite(const Twine &Name, int &ResultFD, +std::error_code openFileForWrite(const Twine &Name, int &ResultFD, sys::fs::OpenFlags Flags, unsigned Mode) { // Verify that we don't have both "append" and "excl". assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && "Cannot specify both 'excl' and 'append' file creation flags!"); - SmallString<128> PathStorage; SmallVector PathUTF16; - if (error_code EC = UTF8ToUTF16(Name.toStringRef(PathStorage), - PathUTF16)) + if (std::error_code EC = widenPath(Name, PathUTF16)) return EC; DWORD CreationDisposition; @@ -859,14 +809,15 @@ error_code openFileForWrite(const Twine &Name, int &ResultFD, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); if (H == INVALID_HANDLE_VALUE) { - error_code EC = windows_error(::GetLastError()); + DWORD LastError = ::GetLastError(); + std::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(errc::is_a_directory); return EC; } @@ -880,11 +831,11 @@ error_code openFileForWrite(const Twine &Name, int &ResultFD, 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 std::error_code(); } } // end namespace fs @@ -902,17 +853,62 @@ bool home_directory(SmallVectorImpl &result) { return true; } +static bool getTempDirEnvVar(const char *Var, SmallVectorImpl &Res) { + SmallVector NameUTF16; + if (windows::UTF8ToUTF16(Var, NameUTF16)) + return false; + + SmallVector Buf; + size_t Size = 1024; + do { + Buf.reserve(Size); + Size = + GetEnvironmentVariableW(NameUTF16.data(), Buf.data(), Buf.capacity()); + if (Size == 0) + return false; + + // Try again with larger buffer. + } while (Size > Buf.capacity()); + Buf.set_size(Size); + + if (windows::UTF16ToUTF8(Buf.data(), Size, Res)) + return false; + return true; +} + +static bool getTempDirEnvVar(SmallVectorImpl &Res) { + const char *EnvironmentVariables[] = {"TMP", "TEMP", "USERPROFILE"}; + for (const char *Env : EnvironmentVariables) { + if (getTempDirEnvVar(Env, Res)) + return true; + } + return false; +} + +void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl &Result) { + (void)ErasedOnReboot; + Result.clear(); + + // Check whether the temporary directory is specified by an environment + // variable. + if (getTempDirEnvVar(Result)) + return; + + // Fall back to a system default. + const char *DefaultResult = "C:\\TEMP"; + Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); +} } // end namespace path namespace windows { -llvm::error_code UTF8ToUTF16(llvm::StringRef utf8, - llvm::SmallVectorImpl &utf16) { +std::error_code UTF8ToUTF16(llvm::StringRef utf8, + llvm::SmallVectorImpl &utf16) { 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()); + return windows_error(::GetLastError()); utf16.reserve(len + 1); utf16.set_size(len); @@ -921,42 +917,54 @@ llvm::error_code UTF8ToUTF16(llvm::StringRef utf8, utf8.size(), utf16.begin(), utf16.size()); if (len == 0) - return llvm::windows_error(::GetLastError()); + return windows_error(::GetLastError()); } // Make utf16 null terminated. utf16.push_back(0); utf16.pop_back(); - return llvm::error_code::success(); + return std::error_code(); } -llvm::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, - llvm::SmallVectorImpl &utf8) { +static +std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, + size_t utf16_len, + llvm::SmallVectorImpl &utf8) { if (utf16_len) { // Get length. - int len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.begin(), + int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.begin(), 0, NULL, NULL); if (len == 0) - return llvm::windows_error(::GetLastError()); + return windows_error(::GetLastError()); utf8.reserve(len); utf8.set_size(len); // Now do the actual conversion. - len = ::WideCharToMultiByte(CP_UTF8, 0, utf16, utf16_len, utf8.data(), + len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, utf8.data(), utf8.size(), NULL, NULL); if (len == 0) - return llvm::windows_error(::GetLastError()); + return windows_error(::GetLastError()); } // Make utf8 null terminated. utf8.push_back(0); utf8.pop_back(); - return llvm::error_code::success(); + return std::error_code(); +} + +std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, + llvm::SmallVectorImpl &utf8) { + return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8); +} + +std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, + llvm::SmallVectorImpl &utf8) { + return UTF16ToCodePage(CP_ACP, utf16, utf16_len, utf8); } } // end namespace windows } // end namespace sys