#include "il2cpp-config.h" #if IL2CPP_USE_GENERIC_MEMORY_MAPPED_FILE #include "os/File.h" #include "os/MemoryMappedFile.h" #include "os/Mutex.h" #include "utils/dynamic_array.h" #include "utils/Memory.h" #include "Baselib.h" #include "Cpp/ReentrantLock.h" namespace il2cpp { namespace os { struct MemoryFileData { MemoryFileData(const char* name, int64_t dataSize) : size(dataSize) { size_t nameSize = strlen(name); mapName = (char*)IL2CPP_MALLOC(nameSize + 1); strcpy(mapName, name); handle = IL2CPP_MALLOC_ZERO((size_t)dataSize); } ~MemoryFileData() { IL2CPP_FREE(mapName); IL2CPP_FREE(handle); } char* mapName; void* handle; int64_t size; }; struct MemoryFilesContext { baselib::ReentrantLock m_Mutex; il2cpp::utils::dynamic_array m_MemoryFiles; il2cpp::utils::dynamic_array m_MemoryFileViews; }; MemoryFilesContext* s_MemoryFilesContext = nullptr; static bool IsMemoryFile(void* possibleMemoryFile) { os::FastAutoLock lock(&s_MemoryFilesContext->m_Mutex); for (il2cpp::utils::dynamic_array::const_iterator it = s_MemoryFilesContext->m_MemoryFiles.begin(); it != s_MemoryFilesContext->m_MemoryFiles.end(); ++it) { if ((*it)->handle == possibleMemoryFile) return true; } return false; } static MemoryFileData* FindMemoryFile(void* possibleMemoryFile) { for (il2cpp::utils::dynamic_array::iterator it = s_MemoryFilesContext->m_MemoryFiles.begin(); it != s_MemoryFilesContext->m_MemoryFiles.end(); ++it) { if ((*it)->handle == possibleMemoryFile) { return *it; } } return NULL; } static MemoryFileData* FindMemoryFile(const char* mapName) { for (il2cpp::utils::dynamic_array::iterator it = s_MemoryFilesContext->m_MemoryFiles.begin(); it != s_MemoryFilesContext->m_MemoryFiles.end(); ++it) { if (strcmp((*it)->mapName, mapName) == 0) { return *it; } } return NULL; } static bool IsMemoryFileView(void* possibleMemoryFile) { os::FastAutoLock lock(&s_MemoryFilesContext->m_Mutex); return std::find(s_MemoryFilesContext->m_MemoryFileViews.begin(), s_MemoryFilesContext->m_MemoryFileViews.end(), possibleMemoryFile) != s_MemoryFilesContext->m_MemoryFileViews.end(); } void MemoryMappedFile::AllocateStaticData() { s_MemoryFilesContext = new MemoryFilesContext(); } void MemoryMappedFile::FreeStaticData() { delete s_MemoryFilesContext; s_MemoryFilesContext = nullptr; } FileHandle* MemoryMappedFile::Create(FileHandle* file, const char* mapName, int32_t mode, int64_t *capacity, MemoryMappedFileAccess access, int32_t options, MemoryMappedFileError* error) { if (file == NULL) { if (mapName != NULL) { os::FastAutoLock lock(&s_MemoryFilesContext->m_Mutex); const MemoryFileData* memoryFileData = FindMemoryFile(mapName); if (memoryFileData != NULL) { file = (FileHandle*)memoryFileData->handle; } else { MemoryFileData* memoryFileData = new MemoryFileData(mapName, *capacity); s_MemoryFilesContext->m_MemoryFiles.push_back(memoryFileData); file = (FileHandle*)memoryFileData->handle; } } } return file; } static MemoryMappedFile::MemoryMappedFileHandle ViewRealFile(FileHandle* mappedFileHandle, int64_t* length, int64_t offset, MemoryMappedFileAccess access, MemoryMappedFileError* error) { int fileError = 0; if (*length == 0) { *length = os::File::GetLength(mappedFileHandle, &fileError); if (fileError != 0) { if (error != NULL) *error = COULD_NOT_MAP_MEMORY; return NULL; } } void* buffer = IL2CPP_MALLOC_ZERO((size_t)*length); os::File::Seek(mappedFileHandle, offset, 0, &fileError); if (fileError != 0) { IL2CPP_FREE(buffer); if (error != NULL) *error = COULD_NOT_MAP_MEMORY; return NULL; } int bytesRead = File::Read(mappedFileHandle, (char*)buffer, (int)*length, &fileError); if (bytesRead != *length || fileError != 0) { IL2CPP_FREE(buffer); if (error != NULL) *error = COULD_NOT_MAP_MEMORY; return NULL; } return buffer; } static MemoryMappedFile::MemoryMappedFileHandle ViewMemoryFile(void* mappedFileHandle, int64_t* length, int64_t offset, MemoryMappedFileAccess access, MemoryMappedFileError* error) { os::FastAutoLock lock(&s_MemoryFilesContext->m_Mutex); const MemoryFileData* memoryFileData = FindMemoryFile(mappedFileHandle); IL2CPP_ASSERT(memoryFileData != NULL); if (*length == 0) *length = memoryFileData->size; if (*length > memoryFileData->size) { if (error != NULL) *error = COULD_NOT_MAP_MEMORY; return NULL; } void* memoryMappedFileView = (uint8_t*)memoryFileData->handle + offset; s_MemoryFilesContext->m_MemoryFileViews.push_back(memoryMappedFileView); return memoryMappedFileView; } MemoryMappedFile::MemoryMappedFileHandle MemoryMappedFile::View(FileHandle* mappedFileHandle, int64_t* length, int64_t offset, MemoryMappedFileAccess access, int64_t* actualOffset, MemoryMappedFileError* error) { IL2CPP_ASSERT(actualOffset != NULL); *actualOffset = offset; if (IsMemoryFile((void*)mappedFileHandle)) return ViewMemoryFile((void*)mappedFileHandle, length, offset, access, error); else return ViewRealFile(mappedFileHandle, length, offset, access, error); } void MemoryMappedFile::Flush(MemoryMappedFileHandle memoryMappedFileData, int64_t length) { } bool MemoryMappedFile::UnmapView(MemoryMappedFileHandle memoryMappedFileData, int64_t length) { if (IsMemoryFileView(memoryMappedFileData)) s_MemoryFilesContext->m_MemoryFileViews.erase_swap_back(&memoryMappedFileData); else if (!IsMemoryFile(memoryMappedFileData)) IL2CPP_FREE(memoryMappedFileData); return true; } bool MemoryMappedFile::Close(FileHandle* file) { os::FastAutoLock lock(&s_MemoryFilesContext->m_Mutex); MemoryFileData* memoryFileData = FindMemoryFile((void*)file); if (memoryFileData != NULL) { delete memoryFileData; s_MemoryFilesContext->m_MemoryFiles.erase_swap_back(&memoryFileData); } return true; } void MemoryMappedFile::ConfigureHandleInheritability(FileHandle* file, bool inheritability) { } bool MemoryMappedFile::OwnsDuplicatedFileHandle(FileHandle* file) { return true; } } } #endif