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=0eb0759d7435538e2481ce959832adbf187fbbd6;hb=7acd886ecfa0adc8a14476eafe8cf1fa981cfe18;hpb=1c881d9d35a7880d0c102119b29d20ceb2ed1975 diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index 0eb0759d743..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. @@ -31,245 +36,84 @@ typedef int errno_t; #endif -using namespace llvm; - -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 UTF8ToUTF16(StringRef utf8, SmallVectorImpl &utf16) { - int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, - utf8.begin(), utf8.size(), - utf16.begin(), 0); - - if (len == 0) - return windows_error(::GetLastError()); - - utf16.reserve(len + 1); - utf16.set_size(len); - - len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, - utf8.begin(), utf8.size(), - utf16.begin(), utf16.size()); - - if (len == 0) - return windows_error(::GetLastError()); - - // Make utf16 null terminated. - utf16.push_back(0); - utf16.pop_back(); - - return error_code::success(); - } - - error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, - SmallVectorImpl &utf8) { - // Get length. - int len = ::WideCharToMultiByte(CP_UTF8, 0, - utf16, utf16_len, - utf8.begin(), 0, - NULL, NULL); - - if (len == 0) - 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(), utf8.size(), - NULL, NULL); - - if (len == 0) - return windows_error(::GetLastError()); +#ifdef _MSC_VER +# pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. +#endif - // Make utf8 null terminated. - utf8.push_back(0); - utf8.pop_back(); +using namespace llvm; - return error_code::success(); - } +using llvm::sys::windows::UTF8ToUTF16; +using llvm::sys::windows::UTF16ToUTF8; - error_code TempDir(SmallVectorImpl &result) { - retry_temp_dir: - DWORD len = ::GetTempPathW(result.capacity(), result.begin()); +static error_code windows_error(DWORD E) { + return mapWindowsError(E); +} - if (len == 0) - return windows_error(::GetLastError()); +static error_code TempDir(SmallVectorImpl &Result) { + SmallVector Res; +retry_temp_dir: + DWORD Len = ::GetTempPathW(Res.capacity(), Res.begin()); - if (len > result.capacity()) { - result.reserve(len); - goto retry_temp_dir; - } + if (Len == 0) + return windows_error(::GetLastError()); - result.set_size(len); - return error_code::success(); + if (Len > Res.capacity()) { + Res.reserve(Len); + goto retry_temp_dir; } - bool is_separator(const wchar_t value) { - switch (value) { - case L'\\': - case L'/': - return true; - default: - return false; - } - } + Res.set_size(Len); + return UTF16ToUTF8(Res.begin(), Res.size(), Result); } -// 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()); - } - } - - // 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)) - 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); +static bool is_separator(const wchar_t value) { + switch (value) { + case L'\\': + case L'/': + return true; + default: + return false; } - // Make random_path_utf16 null terminated. - random_path_utf16.push_back(0); - random_path_utf16.pop_back(); - - HANDLE TempFileHandle; - - 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; - } +namespace llvm { +namespace sys { +namespace fs { - // 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; - } +std::string getMainExecutable(const char *argv0, void *MainExecAddr) { + SmallVector PathName; + DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); - result_fd = fd; - break; - } + // A zero return value indicates a failure other than insufficient space. + if (Size == 0) + return ""; - 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; - } + // Insufficient space is determined by a return value equal to the size of + // the buffer passed in. + if (Size == PathName.capacity()) + return ""; - 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; - } + // On success, GetModuleFileNameW returns the number of characters written to + // the buffer not including the NULL terminator. + PathName.set_size(Size); - // 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; - } + // Convert the result from UTF-16 to UTF-8. + SmallVector PathNameUTF8; + if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) + return ""; - return error_code::success(); + return std::string(PathNameUTF8.data()); } -namespace llvm { -namespace sys { -namespace fs { +UniqueID file_status::getUniqueID() const { + // The file is uniquely identified by the volume serial number along + // with the 64-bit file identifier. + uint64_t FileID = (static_cast(FileIndexHigh) << 32ULL) | + static_cast(FileIndexLow); -std::string getMainExecutable(const char *argv0, void *MainExecAddr) { - char pathname[MAX_PATH]; - DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH); - return ret != MAX_PATH ? pathname : ""; + return UniqueID(VolumeSerialNumber, FileID); } - TimeValue file_status::getLastModificationTime() const { ULARGE_INTEGER UI; UI.LowPart = LastWriteTimeLow; @@ -281,50 +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()); + SmallVector cur_path; + DWORD len = MAX_PATH; - // 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. - if (len > cur_path.capacity()) { + do { cur_path.reserve(len); - goto retry_cur_dir; - } + len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); - cur_path.set_size(len); - // cur_path now holds the current directory in utf-16. Convert to utf-8. - - // Find out how much space we need. Sadly, this function doesn't return the - // size needed unless you tell it the result size is 0, which means you - // _always_ have to call it twice. - len = ::WideCharToMultiByte(CP_UTF8, 0, - cur_path.data(), cur_path.size(), - result.data(), 0, - NULL, NULL); - - if (len == 0) - return make_error_code(windows_error(::GetLastError())); + // A zero return value indicates a failure other than insufficient space. + if (len == 0) + return windows_error(::GetLastError()); - result.reserve(len); - result.set_size(len); - // Now do the actual conversion. - len = ::WideCharToMultiByte(CP_UTF8, 0, - cur_path.data(), cur_path.size(), - result.data(), result.size(), - NULL, NULL); - 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()); - return error_code::success(); + // 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; @@ -333,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; @@ -380,43 +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; - if (error_code ec = status(path, st)) - 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) { @@ -432,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 @@ -481,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) { @@ -530,26 +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(); -} - -error_code getUniqueID(const Twine Path, uint64_t &Result) { - file_status Status; - if (error_code E = status(Path, Status)) - return E; - - // The file is uniquely identified by the volume serial number along - // with the 64-bit file identifier. - Result = (static_cast(Status.FileIndexHigh) << 32ULL) | - static_cast(Status.FileIndexLow); - - // Because the serial number is 32-bits, but we've already used up all 64 - // bits for the file index, XOR the serial number into the high 32 bits of - // the resulting value. We could potentially get collisons from this, but - // the likelihood is low. - Result ^= (static_cast(Status.VolumeSerialNumber) << 32ULL); - - return error_code::success(); + return error_code(); } static bool isReservedName(StringRef path) { @@ -579,29 +360,52 @@ static error_code getStatus(HANDLE FileHandle, file_status &Result) { if (FileHandle == INVALID_HANDLE_VALUE) goto handle_status_error; + switch (::GetFileType(FileHandle)) { + default: + llvm_unreachable("Don't know anything about this file type"); + case FILE_TYPE_UNKNOWN: { + DWORD Err = ::GetLastError(); + if (Err != NO_ERROR) + return windows_error(Err); + Result = file_status(file_type::type_unknown); + return error_code(); + } + case FILE_TYPE_DISK: + break; + case FILE_TYPE_CHAR: + Result = file_status(file_type::character_file); + return error_code(); + case FILE_TYPE_PIPE: + Result = file_status(file_type::fifo_file); + return error_code(); + } + BY_HANDLE_FILE_INFORMATION Info; if (!::GetFileInformationByHandle(FileHandle, &Info)) goto handle_status_error; - Result = file_status( - file_type::regular_file, Info.ftLastWriteTime.dwHighDateTime, - Info.ftLastWriteTime.dwLowDateTime, Info.dwVolumeSerialNumber, - Info.nFileSizeHigh, Info.nFileSizeLow, Info.nFileIndexHigh, - Info.nFileIndexLow); - return error_code::success(); + { + file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? file_type::directory_file + : file_type::regular_file; + Result = + file_status(Type, Info.ftLastWriteTime.dwHighDateTime, + Info.ftLastWriteTime.dwLowDateTime, + Info.dwVolumeSerialNumber, Info.nFileSizeHigh, + Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); + 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 { + else Result = file_status(file_type::status_error); - return EC; - } - return error_code::success(); + return windows_error(LastError); } error_code status(const Twine &path, file_status &result) { @@ -611,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)) @@ -635,26 +439,14 @@ error_code status(const Twine &path, file_status &result) { return getStatus(INVALID_HANDLE_VALUE, result); } - if (attr & FILE_ATTRIBUTE_DIRECTORY) - result = file_status(file_type::directory_file); - else { - ScopedFileHandle h( - ::CreateFileW(path_utf16.begin(), - 0, // Attributes only. + ScopedFileHandle h( + ::CreateFileW(path_utf16.begin(), 0, // Attributes only. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - 0)); + NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)); if (!h) return getStatus(INVALID_HANDLE_VALUE, result); - BY_HANDLE_FILE_INFORMATION Info; - if (!::GetFileInformationByHandle(h, &Info)) - return getStatus(INVALID_HANDLE_VALUE, result); return getStatus(h, result); - } - return error_code::success(); } error_code status(int FD, file_status &Result) { @@ -671,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, @@ -713,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) { @@ -725,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; @@ -735,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, - Size >> 32, - 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) { @@ -798,14 +589,14 @@ 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, mapmode mode, uint64_t length, uint64_t offset, - error_code &ec) + error_code &ec) : Mode(mode) , Size(length) , Mapping() @@ -862,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; } @@ -879,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) @@ -891,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!"); @@ -904,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); } @@ -949,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); @@ -969,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) { @@ -978,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); @@ -1004,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) { @@ -1030,27 +808,158 @@ 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, + 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)) + return EC; + + DWORD CreationDisposition; + if (Flags & F_Excl) + CreationDisposition = CREATE_NEW; + else if (Flags & F_Append) + CreationDisposition = OPEN_ALWAYS; + else + CreationDisposition = CREATE_ALWAYS; + + 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) { + 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 (LastError != ERROR_ACCESS_DENIED) + return EC; + if (is_directory(Name)) + return make_error_code(std::errc::is_a_directory); + return EC; + } + + int OpenFlags = 0; + if (Flags & F_Append) + OpenFlags |= _O_APPEND; + + if (Flags & F_Text) + OpenFlags |= _O_TEXT; + + int FD = ::_open_osfhandle(intptr_t(H), OpenFlags); + if (FD == -1) { + ::CloseHandle(H); + return windows_error(ERROR_INVALID_HANDLE); + } + + ResultFD = FD; + 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) { + if (!utf8.empty()) { + int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), + utf8.size(), utf16.begin(), 0); + + if (len == 0) + return windows_error(::GetLastError()); + + utf16.reserve(len + 1); + utf16.set_size(len); + + len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.begin(), + utf8.size(), utf16.begin(), utf16.size()); + + if (len == 0) + return windows_error(::GetLastError()); + } + + // Make utf16 null terminated. + utf16.push_back(0); + utf16.pop_back(); + + return llvm::error_code(); +} + +llvm::error_code UTF16ToUTF8(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(), + 0, NULL, NULL); + + if (len == 0) + 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(), + utf8.size(), NULL, NULL); + + if (len == 0) + return windows_error(::GetLastError()); + } + + // Make utf8 null terminated. + utf8.push_back(0); + utf8.pop_back(); + + return llvm::error_code(); +} +} // end namespace windows } // end namespace sys } // end namespace llvm