251 lines
7.3 KiB
C++
Raw Normal View History

2026-06-23 09:54:30 +08:00
#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<std::string> Directory::GetFileSystemEntries(const std::string& path, const std::string& pathWithPattern, int32_t attrs, int32_t mask, int* error)
{
*error = kErrorCodeSuccess;
std::set<std::string> 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<Il2CppNativeChar>& 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<Il2CppNativeChar>& 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<os::ErrorCode>(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<os::ErrorCode>(GetLastError());
*resultFileName = findData.cFileName;
*resultAttributes = findData.dwFileAttributes;
return os::kErrorCodeSuccess;
}
int32_t Directory::CloseOSFindHandleDirectly(intptr_t osHandle)
{
return ::FindClose((HANDLE)osHandle);
}
}
}
#endif