123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625 |
- #include "il2cpp-config.h"
- #if IL2CPP_TARGET_WINDOWS
- #include "WindowsHelpers.h"
- #undef CopyFile
- #undef DeleteFile
- #undef MoveFile
- #undef ReplaceFile
- #undef GetFileAttributes
- #undef SetFileAttributes
- #undef CreatePipe
- #include "os/File.h"
- #include "utils/Expected.h"
- #include "utils/Il2CppError.h"
- #include "utils/StringUtils.h"
- #include "utils/PathUtils.h"
- #if IL2CPP_TARGET_WINRT
- #include "os/BrokeredFileSystem.h"
- #endif
- #include <stdint.h>
- static inline int FileWin32ErrorToErrorCode(DWORD win32ErrorCode)
- {
- return win32ErrorCode;
- }
- namespace il2cpp
- {
- namespace os
- {
- #if IL2CPP_TARGET_WINDOWS_DESKTOP
- utils::Expected<bool> File::Isatty(FileHandle* fileHandle)
- {
- DWORD mode;
- return GetConsoleMode((HANDLE)fileHandle, &mode) != 0;
- }
- #elif IL2CPP_TARGET_WINDOWS_GAMES
- utils::Expected<bool> File::Isatty(FileHandle* fileHandle)
- {
- return utils::Il2CppError(utils::NotSupported, "Console functions are not supported on Windows Games platforms.");
- }
- #endif
- #if IL2CPP_TARGET_WINDOWS_DESKTOP || IL2CPP_TARGET_WINDOWS_GAMES
- FileHandle* File::GetStdInput()
- {
- return (FileHandle*)GetStdHandle(STD_INPUT_HANDLE);
- }
- FileHandle* File::GetStdError()
- {
- return (FileHandle*)GetStdHandle(STD_ERROR_HANDLE);
- }
- FileHandle* File::GetStdOutput()
- {
- return (FileHandle*)GetStdHandle(STD_OUTPUT_HANDLE);
- }
- #endif // IL2CPP_TARGET_WINDOWS_DESKTOP || IL2CPP_TARGET_WINDOWS_GAMES
- utils::Expected<bool> File::CreatePipe(FileHandle** read_handle, FileHandle** write_handle)
- {
- int error;
- return CreatePipe(read_handle, write_handle, &error);
- }
- utils::Expected<bool> File::CreatePipe(FileHandle** read_handle, FileHandle** write_handle, int* error)
- {
- #if IL2CPP_TARGET_WINDOWS_DESKTOP || IL2CPP_TARGET_WINDOWS_GAMES
- SECURITY_ATTRIBUTES attr;
- attr.nLength = sizeof(SECURITY_ATTRIBUTES);
- attr.bInheritHandle = TRUE;
- attr.lpSecurityDescriptor = NULL;
- bool ret = ::CreatePipe((PHANDLE)read_handle, (PHANDLE)write_handle, &attr, 0);
- if (ret == FALSE)
- {
- *error = GetLastError();
- /* FIXME: throw an exception? */
- return false;
- }
- return true;
- #else // IL2CPP_TARGET_WINDOWS_DESKTOP || IL2CPP_TARGET_WINDOWS_GAMES
- return utils::Il2CppError(utils::NotSupported, "Pipes are not supported on WinRT based platforms.");
- #endif // IL2CPP_TARGET_WINDOWS_DESKTOP || IL2CPP_TARGET_WINDOWS_GAMES
- }
- #if !IL2CPP_TARGET_XBOXONE && !IL2CPP_TARGET_WINDOWS_GAMES
- UnityPalFileAttributes File::GetFileAttributes(const std::string& path, int *error)
- {
- const UTF16String utf16Path(utils::StringUtils::Utf8ToUtf16(path.c_str()));
- WIN32_FILE_ATTRIBUTE_DATA fileAttributes;
- BOOL result = ::GetFileAttributesExW((LPCWSTR)utf16Path.c_str(), GetFileExInfoStandard, &fileAttributes);
- if (result == FALSE)
- {
- auto lastError = ::GetLastError();
- #if IL2CPP_TARGET_WINRT
- if (lastError == ERROR_ACCESS_DENIED)
- return BrokeredFileSystem::GetFileAttributesW(utf16Path, error);
- #endif
- *error = FileWin32ErrorToErrorCode(lastError);
- return static_cast<UnityPalFileAttributes>(INVALID_FILE_ATTRIBUTES);
- }
- *error = kErrorCodeSuccess;
- return static_cast<UnityPalFileAttributes>(fileAttributes.dwFileAttributes);
- }
- #endif // !IL2CPP_TARGET_XBOXONE && !IL2CPP_TARGET_WINDOWS_GAMES
- bool File::SetFileAttributes(const std::string& path, UnityPalFileAttributes attributes, int* error)
- {
- const UTF16String utf16Path(utils::StringUtils::Utf8ToUtf16(path.c_str()));
- *error = kErrorCodeSuccess;
- if (::SetFileAttributesW((LPCWSTR)utf16Path.c_str(), attributes))
- return true;
- auto lastError = ::GetLastError();
- #if IL2CPP_TARGET_WINRT
- if (lastError == ERROR_ACCESS_DENIED)
- return BrokeredFileSystem::SetFileAttributesW(utf16Path, attributes, error);
- #endif
- *error = FileWin32ErrorToErrorCode(lastError);
- return false;
- }
- static inline int64_t HighAndLowToInt64(uint32_t high, uint32_t low)
- {
- return ((uint64_t)high << 32) + low;
- }
- static inline int64_t FileTimeToInt64(const FILETIME& fileTime)
- {
- return HighAndLowToInt64(fileTime.dwHighDateTime, fileTime.dwLowDateTime);
- }
- bool File::GetFileStat(const std::string& path, il2cpp::os::FileStat * stat, int* error)
- {
- *error = kErrorCodeSuccess;
- const UTF16String utf16Path(utils::StringUtils::Utf8ToUtf16(path.c_str()));
- WIN32_FILE_ATTRIBUTE_DATA data;
- if (!::GetFileAttributesExW((LPCWSTR)utf16Path.c_str(), GetFileExInfoStandard, &data))
- {
- auto lastError = ::GetLastError();
- #if IL2CPP_TARGET_WINRT
- if (lastError == ERROR_ACCESS_DENIED)
- return BrokeredFileSystem::GetFileStat(path, utf16Path, stat, error);
- #endif
- *error = FileWin32ErrorToErrorCode(lastError);
- return false;
- }
- stat->name = il2cpp::utils::PathUtils::Basename(path);
- stat->attributes = data.dwFileAttributes;
- stat->creation_time = FileTimeToInt64(data.ftCreationTime);
- stat->last_access_time = FileTimeToInt64(data.ftLastAccessTime);
- stat->last_write_time = FileTimeToInt64(data.ftLastWriteTime);
- stat->length = HighAndLowToInt64(data.nFileSizeHigh, data.nFileSizeLow);
- return true;
- }
- FileType File::GetFileType(FileHandle* handle)
- {
- int result = ::GetFileType((HANDLE)handle);
- /*if (result == FILE_TYPE_UNKNOWN)
- {
- *error = GetLastError();
- }*/
- return (FileType)result;
- }
- bool File::CopyFile(const std::string& src, const std::string& dest, bool overwrite, int* error)
- {
- const UTF16String utf16Src(utils::StringUtils::Utf8ToUtf16(src.c_str()));
- const UTF16String utf16Dest(utils::StringUtils::Utf8ToUtf16(dest.c_str()));
- *error = kErrorCodeSuccess;
- if (::CopyFileW((LPWSTR)utf16Src.c_str(), (LPWSTR)utf16Dest.c_str(), overwrite ? FALSE : TRUE))
- return true;
- auto lastError = ::GetLastError();
- #if IL2CPP_TARGET_WINRT
- if (lastError == ERROR_ACCESS_DENIED)
- return BrokeredFileSystem::CopyFileW(utf16Src, utf16Dest, overwrite, error);
- #endif
- *error = FileWin32ErrorToErrorCode(lastError);
- return false;
- }
- bool File::MoveFile(const std::string& src, const std::string& dest, int* error)
- {
- const UTF16String utf16Src(utils::StringUtils::Utf8ToUtf16(src.c_str()));
- const UTF16String utf16Dest(utils::StringUtils::Utf8ToUtf16(dest.c_str()));
- *error = kErrorCodeSuccess;
- if (::MoveFileExW((LPWSTR)utf16Src.c_str(), (LPWSTR)utf16Dest.c_str(), MOVEFILE_COPY_ALLOWED))
- return true;
- auto lastError = ::GetLastError();
- #if IL2CPP_TARGET_WINRT
- if (lastError == ERROR_ACCESS_DENIED)
- return BrokeredFileSystem::MoveFileW(utf16Src, utf16Dest, error);
- #endif
- *error = FileWin32ErrorToErrorCode(lastError);
- return false;
- }
- bool File::DeleteFile(const std::string& path, int *error)
- {
- *error = kErrorCodeSuccess;
- const UTF16String utf16Path(utils::StringUtils::Utf8ToUtf16(path.c_str()));
- if (::DeleteFileW((LPWSTR)utf16Path.c_str()))
- return true;
- auto lastError = ::GetLastError();
- #if IL2CPP_TARGET_WINRT
- if (lastError == ERROR_ACCESS_DENIED)
- {
- *error = BrokeredFileSystem::DeleteFileW(utf16Path);
- return *error == kErrorCodeSuccess;
- }
- #endif
- *error = FileWin32ErrorToErrorCode(lastError);
- return false;
- }
- bool File::ReplaceFile(const std::string& sourceFileName, const std::string& destinationFileName, const std::string& destinationBackupFileName, bool ignoreMetadataErrors, int* error)
- {
- const UTF16String utf16Src(utils::StringUtils::Utf8ToUtf16(sourceFileName.c_str()));
- const UTF16String utf16Dest(utils::StringUtils::Utf8ToUtf16(destinationFileName.c_str()));
- const UTF16String utf16Backup(utils::StringUtils::Utf8ToUtf16(destinationBackupFileName.c_str()));
- *error = kErrorCodeSuccess;
- DWORD flags = REPLACEFILE_WRITE_THROUGH;
- if (ignoreMetadataErrors)
- flags |= REPLACEFILE_IGNORE_MERGE_ERRORS;
- if (::ReplaceFileW((LPWSTR)utf16Dest.c_str(), (LPWSTR)utf16Src.c_str(), utf16Backup.empty() ? NULL : (LPWSTR)utf16Backup.c_str(), flags, NULL, NULL))
- return true;
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return false;
- }
- static inline int MonoToWindowsOpenMode(int monoOpenMode)
- {
- switch (monoOpenMode)
- {
- case kFileModeCreateNew:
- return CREATE_NEW;
- case kFileModeCreate:
- return CREATE_ALWAYS;
- case kFileModeOpen:
- return OPEN_EXISTING;
- case kFileModeOpenOrCreate:
- case kFileModeAppend:
- return OPEN_ALWAYS;
- case kFileModeTruncate:
- return TRUNCATE_EXISTING;
- default:
- Assert(false && "Unknown mono open mode");
- IL2CPP_UNREACHABLE;
- }
- }
- static inline int MonoToWindowsAccessMode(int monoAccessMode)
- {
- switch (monoAccessMode)
- {
- case kFileAccessRead:
- return GENERIC_READ;
- case kFileAccessWrite:
- return GENERIC_WRITE;
- case kFileAccessExecute:
- return GENERIC_EXECUTE;
- case kFileAccessReadWrite:
- return GENERIC_READ | GENERIC_WRITE;
- case kFileAccessReadWriteExecute:
- return GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE;
- default:
- return 0;
- }
- }
- static inline DWORD MonoOptionsToWindowsFlagsAndAttributes(const std::string& path, int options)
- {
- DWORD flagsAndAttributes;
- if (options != 0)
- {
- if (options & kFileOptionsEncrypted)
- flagsAndAttributes = FILE_ATTRIBUTE_ENCRYPTED;
- else
- flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
- if (options & kFileOptionsDeleteOnClose)
- flagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
- if (options & kFileOptionsSequentialScan)
- flagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
- if (options & kFileOptionsRandomAccess)
- flagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
- if (options & kFileOptionsWriteThrough)
- flagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
- }
- else
- {
- flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
- }
- int error;
- UnityPalFileAttributes currentAttributes = File::GetFileAttributes(path, &error);
- if (currentAttributes != INVALID_FILE_ATTRIBUTES && (currentAttributes & FILE_ATTRIBUTE_DIRECTORY))
- flagsAndAttributes |= FILE_FLAG_BACKUP_SEMANTICS; // Required to open a directory
- return flagsAndAttributes;
- }
- FileHandle* File::Open(const std::string& path, int openMode, int accessMode, int shareMode, int options, int *error)
- {
- const UTF16String utf16Path(utils::StringUtils::Utf8ToUtf16(path.c_str()));
- openMode = MonoToWindowsOpenMode(openMode);
- accessMode = MonoToWindowsAccessMode(accessMode);
- DWORD flagsAndAttributes = MonoOptionsToWindowsFlagsAndAttributes(path, options);
- HANDLE handle = ::CreateFileW((LPCWSTR)utf16Path.c_str(), accessMode, shareMode, NULL, openMode, flagsAndAttributes, NULL);
- if (INVALID_HANDLE_VALUE == handle)
- {
- auto lastError = ::GetLastError();
- #if IL2CPP_TARGET_WINRT
- if (lastError == ERROR_ACCESS_DENIED)
- return BrokeredFileSystem::Open(utf16Path, accessMode, shareMode, openMode, flagsAndAttributes, error);
- #endif
- *error = FileWin32ErrorToErrorCode(lastError);
- return (FileHandle*)INVALID_HANDLE_VALUE;
- }
- *error = kErrorCodeSuccess;
- return (FileHandle*)handle;
- }
- bool File::Close(FileHandle* handle, int *error)
- {
- *error = kErrorCodeSuccess;
- if (CloseHandle((HANDLE)handle))
- return true;
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return false;
- }
- bool File::SetFileTime(FileHandle* handle, int64_t creation_time, int64_t last_access_time, int64_t last_write_time, int* error)
- {
- FILE_BASIC_INFO fileInfo;
- fileInfo.CreationTime.QuadPart = creation_time;
- fileInfo.LastAccessTime.QuadPart = last_access_time;
- fileInfo.LastWriteTime.QuadPart = last_write_time;
- fileInfo.ChangeTime.QuadPart = 0; // 0 means don't change anything
- fileInfo.FileAttributes = 0; // 0 means don't change anything
- if (SetFileInformationByHandle(handle, FileBasicInfo, &fileInfo, sizeof(FILE_BASIC_INFO)) == FALSE)
- {
- *error = GetLastError();
- return false;
- }
- *error = kErrorCodeSuccess;
- return true;
- }
- int64_t File::GetLength(FileHandle* handle, int *error)
- {
- *error = kErrorCodeSuccess;
- LARGE_INTEGER size;
- if (!::GetFileSizeEx((HANDLE)handle, &size))
- {
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return 0;
- }
- return size.QuadPart;
- }
- #if !IL2CPP_USE_GENERIC_FILE
- bool File::Truncate(FileHandle* handle, int *error)
- {
- *error = kErrorCodeSuccess;
- if (!::SetEndOfFile((HANDLE)handle))
- {
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return false;
- }
- return true;
- }
- #endif // IL2CPP_USE_GENERIC_FILE
- bool File::SetLength(FileHandle* handle, int64_t length, int *error)
- {
- *error = kErrorCodeSuccess;
- LARGE_INTEGER zeroOffset = { 0 };
- LARGE_INTEGER requestedOffset = { 0 };
- requestedOffset.QuadPart = length;
- LARGE_INTEGER initialPosition = { 0 };
- // set position to 0 from current to retrieve current position
- if (!::SetFilePointerEx((HANDLE)handle, zeroOffset, &initialPosition, FILE_CURRENT))
- {
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return false;
- }
- // seek to requested length
- if (!::SetFilePointerEx((HANDLE)handle, requestedOffset, NULL, FILE_BEGIN))
- {
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return false;
- }
- // set requested length
- if (!::SetEndOfFile((HANDLE)handle))
- {
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return false;
- }
- // restore original position
- if (!::SetFilePointerEx((HANDLE)handle, initialPosition, NULL, FILE_BEGIN))
- {
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return false;
- }
- return true;
- }
- int64_t File::Seek(FileHandle* handle, int64_t offset, int origin, int *error)
- {
- *error = kErrorCodeSuccess;
- LARGE_INTEGER distance;
- distance.QuadPart = offset;
- LARGE_INTEGER position = { 0 };
- if (!::SetFilePointerEx((HANDLE)handle, distance, &position, origin))
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return position.QuadPart;
- }
- int File::Read(FileHandle* handle, char *dest, int count, int *error)
- {
- *error = kErrorCodeSuccess;
- DWORD bytesRead = 0;
- if (!::ReadFile(handle, dest, count, &bytesRead, NULL))
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return bytesRead;
- }
- int32_t File::Write(FileHandle* handle, const char* buffer, int count, int *error)
- {
- int32_t written;
- BOOL success = WriteFile((HANDLE)handle, buffer, count, (LPDWORD)&written, NULL);
- if (!success)
- {
- DWORD originalError = GetLastError();
- if (originalError == ERROR_INVALID_PARAMETER)
- {
- // Maybe this is an async file write, so try with those parameters.
- OVERLAPPED overlapped = {0};
- success = WriteFile((HANDLE)handle, buffer, count, NULL, &overlapped);
- if (success != 0 || GetLastError() == ERROR_IO_PENDING)
- {
- success = TRUE;
- // The async write succeeded. Now get the number of bytes written.
- #if IL2CPP_TARGET_WINDOWS_DESKTOP
- if (GetOverlappedResult((HANDLE)handle, &overlapped, (LPDWORD)&written, TRUE) == 0)
- #else
- if (GetOverlappedResultEx((HANDLE)handle, &overlapped, (LPDWORD)&written, INFINITE, FALSE) == 0)
- #endif
- {
- // Oops, we could not get the number of bytes writen, so return an error.
- *error = GetLastError();
- return -1;
- }
- }
- }
- if (!success)
- {
- *error = originalError;
- return -1;
- }
- }
- return written;
- }
- bool File::Flush(FileHandle* handle, int* error)
- {
- *error = kErrorCodeSuccess;
- if (FlushFileBuffers((HANDLE)handle))
- return true;
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- return false;
- }
- void File::Lock(FileHandle* handle, int64_t position, int64_t length, int* error)
- {
- *error = kErrorCodeSuccess;
- OVERLAPPED overlapped;
- ZeroMemory(&overlapped, sizeof(overlapped));
- overlapped.Offset = position & 0xFFFFFFFF;
- overlapped.OffsetHigh = position >> 32;
- LARGE_INTEGER lengthUnion;
- lengthUnion.QuadPart = length;
- if (!::LockFileEx((HANDLE)handle, LOCKFILE_FAIL_IMMEDIATELY, 0, lengthUnion.LowPart, lengthUnion.HighPart, &overlapped))
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- }
- void File::Unlock(FileHandle* handle, int64_t position, int64_t length, int* error)
- {
- *error = kErrorCodeSuccess;
- OVERLAPPED overlapped;
- ZeroMemory(&overlapped, sizeof(overlapped));
- overlapped.Offset = position & 0xFFFFFFFF;
- overlapped.OffsetHigh = position >> 32;
- LARGE_INTEGER lengthUnion;
- lengthUnion.QuadPart = length;
- if (!::UnlockFileEx((HANDLE)handle, 0, lengthUnion.LowPart, lengthUnion.HighPart, &overlapped))
- *error = FileWin32ErrorToErrorCode(::GetLastError());
- }
- utils::Expected<bool> File::DuplicateHandle(FileHandle* source_process_handle, FileHandle* source_handle, FileHandle* target_process_handle,
- FileHandle** target_handle, int access, int inherit, int options, int* error)
- {
- /* This is only used on Windows */
- //MONO_PREPARE_BLOCKING;
- BOOL ret = ::DuplicateHandle((HANDLE)source_process_handle, (HANDLE)source_handle, (HANDLE)target_process_handle, (LPHANDLE)target_handle, access, inherit, options);
- //MONO_FINISH_BLOCKING;
- if (ret == FALSE)
- {
- *error = GetLastError();
- /* FIXME: throw an exception? */
- return false;
- }
- return true;
- }
- static bool ends_with(const std::string& value, const std::string& ending)
- {
- if (value.length() >= ending.length())
- return value.compare(value.length() - ending.length(), ending.length(), ending) == 0;
- return false;
- }
- utils::Expected<bool> File::IsExecutable(const std::string& path)
- {
- return ends_with(path, "exe");
- }
- bool File::Cancel(FileHandle* handle)
- {
- return CancelIoEx((HANDLE)handle, NULL);
- }
- }
- }
- #endif
|