#include "il2cpp-config.h" #if IL2CPP_TARGET_WINDOWS #include "WindowsHeaders.h" #undef FindFirstFile #undef FindNextFile #include "os/Directory.h" #include "os/ErrorCodes.h" #include "utils/StringUtils.h" #include "utils/PathUtils.h" #if IL2CPP_TARGET_WINRT #include "os/BrokeredFileSystem.h" #endif static inline int DirectoryWin32ErrorToErrorCode(DWORD win32ErrorCode) { return win32ErrorCode; } using namespace il2cpp::utils::PathUtils; namespace il2cpp { namespace os { std::string Directory::GetCurrent(int *error) { UTF16String buf; int len, res_len; len = MAX_PATH + 1; buf.resize(len, 0); *error = ERROR_SUCCESS; res_len = ::GetCurrentDirectory(len, (LPWSTR)buf.c_str()); if (res_len > len) /*buf is too small.*/ { int old_res_len = res_len; buf.resize(res_len, 0); res_len = ::GetCurrentDirectory(res_len, (LPWSTR)buf.c_str()) == old_res_len; } std::string directory; if (res_len) { len = 0; while (buf[len]) ++len; directory = il2cpp::utils::StringUtils::Utf16ToUtf8(buf.c_str()); } else { *error = DirectoryWin32ErrorToErrorCode(::GetLastError()); } return directory; } bool Directory::SetCurrent(const std::string& path, int* error) { *error = kErrorCodeSuccess; const UTF16String utf16Path(il2cpp::utils::StringUtils::Utf8ToUtf16(path.c_str())); if (::SetCurrentDirectory((LPWSTR)utf16Path.c_str())) return true; *error = DirectoryWin32ErrorToErrorCode(::GetLastError()); return false; } bool Directory::Create(const std::string& path, int *error) { *error = kErrorCodeSuccess; const UTF16String utf16Path(il2cpp::utils::StringUtils::Utf8ToUtf16(path.c_str())); if (::CreateDirectory((LPWSTR)utf16Path.c_str(), NULL)) return true; auto lastError = ::GetLastError(); #if IL2CPP_TARGET_WINRT if (lastError == ERROR_ACCESS_DENIED) { *error = BrokeredFileSystem::CreateDirectoryW(utf16Path); return *error == kErrorCodeSuccess; } #endif *error = DirectoryWin32ErrorToErrorCode(lastError); return false; } bool Directory::Remove(const std::string& path, int *error) { *error = kErrorCodeSuccess; const UTF16String utf16Path(il2cpp::utils::StringUtils::Utf8ToUtf16(path.c_str())); if (::RemoveDirectory((LPWSTR)utf16Path.c_str())) return true; auto lastError = ::GetLastError(); #if IL2CPP_TARGET_WINRT if (lastError == ERROR_ACCESS_DENIED) { *error = BrokeredFileSystem::RemoveDirectoryW(utf16Path); return *error == kErrorCodeSuccess; } #endif *error = DirectoryWin32ErrorToErrorCode(lastError); return false; } std::set Directory::GetFileSystemEntries(const std::string& path, const std::string& pathWithPattern, int32_t attrs, int32_t mask, int* error) { *error = kErrorCodeSuccess; std::set files; WIN32_FIND_DATA ffd; const UTF16String utf16Path(il2cpp::utils::StringUtils::Utf8ToUtf16(pathWithPattern)); HANDLE handle = ::FindFirstFileExW((LPCWSTR)utf16Path.c_str(), FindExInfoStandard, &ffd, FindExSearchNameMatch, NULL, 0); if (INVALID_HANDLE_VALUE == handle) { auto lastError = ::GetLastError(); #if IL2CPP_TARGET_WINRT if (lastError == ERROR_ACCESS_DENIED) return BrokeredFileSystem::GetFileSystemEntries(utils::StringUtils::Utf8ToUtf16(path), utf16Path, attrs, mask, error); #endif // Following the Mono implementation, do not treat a directory with no files as an error. int errorCode = DirectoryWin32ErrorToErrorCode(lastError); if (errorCode != ERROR_FILE_NOT_FOUND) *error = errorCode; return files; } do { const std::string fileName(il2cpp::utils::StringUtils::Utf16ToUtf8(ffd.cFileName)); if ((fileName.length() == 1 && fileName.at(0) == '.') || (fileName.length() == 2 && fileName.at(0) == '.' && fileName.at(1) == '.')) continue; if ((ffd.dwFileAttributes & mask) == attrs) { files.insert(Combine(path, fileName)); } } while (::FindNextFileW(handle, &ffd) != 0); ::FindClose(handle); return files; } Directory::FindHandle::FindHandle(const utils::StringView& searchPathWithPattern) : osHandle(INVALID_HANDLE_VALUE), handleFlags(os::kNoFindHandleFlags), directoryPath(il2cpp::utils::PathUtils::DirectoryName(searchPathWithPattern)), pattern(il2cpp::utils::PathUtils::Basename(searchPathWithPattern)) { } Directory::FindHandle::~FindHandle() { IL2CPP_ASSERT(osHandle == INVALID_HANDLE_VALUE); } int32_t Directory::FindHandle::CloseOSHandle() { int32_t result = os::kErrorCodeSuccess; if (osHandle != INVALID_HANDLE_VALUE) { #if IL2CPP_TARGET_WINRT if (handleFlags & kUseBrokeredFileSystem) { result = BrokeredFileSystem::FindClose(osHandle); } else #endif { result = ::FindClose(osHandle); } osHandle = INVALID_HANDLE_VALUE; } return result; } os::ErrorCode Directory::FindFirstFile(FindHandle* findHandle, const utils::StringView& searchPathWithPattern, Il2CppNativeString* resultFileName, int32_t* resultAttributes) { WIN32_FIND_DATA findData; HANDLE handle = FindFirstFileExW(searchPathWithPattern.Str(), FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, 0); if (handle != INVALID_HANDLE_VALUE) { findHandle->SetOSHandle(handle); *resultFileName = findData.cFileName; *resultAttributes = findData.dwFileAttributes; return os::kErrorCodeSuccess; } else { auto lastError = GetLastError(); #if IL2CPP_TARGET_WINRT if (lastError == ERROR_ACCESS_DENIED) return BrokeredFileSystem::FindFirstFileW(findHandle, searchPathWithPattern, resultFileName, resultAttributes); #endif return static_cast(lastError); } } os::ErrorCode Directory::FindNextFile(FindHandle* findHandle, Il2CppNativeString* resultFileName, int32_t* resultAttributes) { #if IL2CPP_TARGET_WINRT if (findHandle->handleFlags & kUseBrokeredFileSystem) return BrokeredFileSystem::FindNextFileW(findHandle, resultFileName, resultAttributes); #endif WIN32_FIND_DATA findData; if (FindNextFileW(findHandle->osHandle, &findData) == FALSE) return static_cast(GetLastError()); *resultFileName = findData.cFileName; *resultAttributes = findData.dwFileAttributes; return os::kErrorCodeSuccess; } int32_t Directory::CloseOSFindHandleDirectly(intptr_t osHandle) { return ::FindClose((HANDLE)osHandle); } } } #endif