123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- #include "il2cpp-config.h"
- #if !IL2CPP_USE_GENERIC_MEMORY_MAPPED_FILE && IL2CPP_TARGET_POSIX && !RUNTIME_TINY
- #include <sys/mman.h>
- #include <map>
- #include "os/File.h"
- #include "os/MemoryMappedFile.h"
- #include "os/Mutex.h"
- #include "utils/Memory.h"
- #include "FileHandle.h"
- #include <unistd.h>
- #include <fcntl.h>
- #ifdef DEFFILEMODE
- #define DEFAULT_FILEMODE DEFFILEMODE
- #else
- #define DEFAULT_FILEMODE 0666
- #endif
- #ifndef MAP_32BIT
- #define MAP_32BIT 0
- #endif
- #define MMAP_PAGE_SIZE 4096
- namespace il2cpp
- {
- namespace os
- {
- enum MemoryMappedFileFlags
- {
- /* protection */
- MONO_MMAP_NONE = 0,
- MONO_MMAP_READ = 1 << 0,
- MONO_MMAP_WRITE = 1 << 1,
- MONO_MMAP_EXEC = 1 << 2,
- /* make the OS discard the dirty data and fill with 0 */
- MONO_MMAP_DISCARD = 1 << 3,
- /* other flags (add commit, sync) */
- MONO_MMAP_PRIVATE = 1 << 4,
- MONO_MMAP_SHARED = 1 << 5,
- MONO_MMAP_ANON = 1 << 6,
- MONO_MMAP_FIXED = 1 << 7,
- MONO_MMAP_32BIT = 1 << 8
- };
- static bool IsSpecialZeroSizeFile(struct stat *buf)
- {
- return buf->st_size == 0 && (buf->st_mode & (S_IFCHR | S_IFBLK | S_IFIFO | S_IFSOCK)) != 0;
- }
- static int64_t AlignUpToPageSize(int64_t size)
- {
- int64_t page_size = MMAP_PAGE_SIZE;
- return (size + page_size - 1) & ~(page_size - 1);
- }
- static int64_t AlignDownToPageSize(int64_t size)
- {
- int64_t page_size = MMAP_PAGE_SIZE;
- return size & ~(page_size - 1);
- }
- static int ConvertAccessToMemoryMappedFileFlags(int access)
- {
- switch (access)
- {
- case MMAP_FILE_ACCESS_READ_WRITE:
- return MONO_MMAP_WRITE | MONO_MMAP_READ | MONO_MMAP_SHARED;
- case MMAP_FILE_ACCESS_WRITE:
- return MONO_MMAP_WRITE | MONO_MMAP_SHARED;
- case MMAP_FILE_ACCESS_COPY_ON_WRITE:
- return MONO_MMAP_WRITE | MONO_MMAP_READ | MONO_MMAP_PRIVATE;
- case MMAP_FILE_ACCESS_READ_EXECUTE:
- return MONO_MMAP_EXEC | MONO_MMAP_PRIVATE | MONO_MMAP_SHARED;
- case MMAP_FILE_ACCESS_READ_WRITE_EXECUTE:
- return MONO_MMAP_WRITE | MONO_MMAP_READ | MONO_MMAP_EXEC | MONO_MMAP_SHARED;
- case MMAP_FILE_ACCESS_READ:
- return MONO_MMAP_READ | MONO_MMAP_SHARED;
- default:
- IL2CPP_ASSERT("unknown MemoryMappedFileAccess");
- }
- return 0;
- }
- static int ConvertFileModeToUnix(int mode)
- {
- switch (mode)
- {
- case FILE_MODE_CREATE_NEW:
- return O_CREAT | O_EXCL;
- case FILE_MODE_CREATE:
- return O_CREAT | O_TRUNC;
- case FILE_MODE_OPEN:
- return 0;
- case FILE_MODE_OPEN_OR_CREATE:
- return O_CREAT;
- case FILE_MODE_TRUNCATE:
- return O_TRUNC;
- case FILE_MODE_APPEND:
- return O_APPEND;
- default:
- IL2CPP_ASSERT("unknown FileMode");
- }
- return 0;
- }
- static int ConvertAccessModeToUnix(int access)
- {
- switch (access)
- {
- case MMAP_FILE_ACCESS_READ_WRITE:
- case MMAP_FILE_ACCESS_COPY_ON_WRITE:
- case MMAP_FILE_ACCESS_READ_WRITE_EXECUTE:
- return O_RDWR;
- case MMAP_FILE_ACCESS_READ:
- case MMAP_FILE_ACCESS_READ_EXECUTE:
- return O_RDONLY;
- case MMAP_FILE_ACCESS_WRITE:
- return O_WRONLY;
- default:
- IL2CPP_ASSERT("unknown MemoryMappedFileAccess");
- }
- return 0;
- }
- static int ConvertFlagsToProt(int flags)
- {
- int prot = PROT_NONE;
- /* translate the protection bits */
- if (flags & MONO_MMAP_READ)
- prot |= PROT_READ;
- if (flags & MONO_MMAP_WRITE)
- prot |= PROT_WRITE;
- if (flags & MONO_MMAP_EXEC)
- prot |= PROT_EXEC;
- return prot;
- }
- FileHandle* MemoryMappedFile::Create(FileHandle* file, const char* mapName, int32_t mode, int64_t *capacity, MemoryMappedFileAccess access, int32_t options, MemoryMappedFileError* error)
- {
- struct stat buf;
- int result, fd;
- if (file != NULL)
- result = fstat(file->fd, &buf);
- else
- result = stat(mapName, &buf);
- if (mode == FILE_MODE_TRUNCATE || mode == FILE_MODE_APPEND || mode == FILE_MODE_OPEN)
- {
- if (result == -1)
- {
- if (error != NULL)
- *error = FILE_NOT_FOUND;
- return NULL;
- }
- }
- if (mode == FILE_MODE_CREATE_NEW && result == 0)
- {
- if (error != NULL)
- *error = FILE_ALREADY_EXISTS;
- return NULL;
- }
- if (result == 0)
- {
- if (*capacity == 0)
- {
- /**
- * Special files such as FIFOs, sockets, and devices can have a size of 0. Specifying a capacity for these
- * also makes little sense, so don't do the check if th file is one of these.
- */
- if (buf.st_size == 0 && !IsSpecialZeroSizeFile(&buf))
- {
- if (error != NULL)
- *error = CAPACITY_SMALLER_THAN_FILE_SIZE;
- return NULL;
- }
- *capacity = buf.st_size;
- }
- else if (*capacity < buf.st_size)
- {
- if (error != NULL)
- *error = CAPACITY_SMALLER_THAN_FILE_SIZE;
- return NULL;
- }
- }
- else
- {
- if (mode == FILE_MODE_CREATE_NEW && *capacity == 0)
- {
- if (error != NULL)
- *error = CAPACITY_SMALLER_THAN_FILE_SIZE;
- return NULL;
- }
- }
- bool ownsFd = true;
- if (file != NULL)
- {
- #if IL2CPP_HAS_DUP
- fd = dup(file->fd);
- #else
- fd = file->fd;
- ownsFd = false;
- #endif
- }
- else
- {
- fd = open(mapName, ConvertFileModeToUnix(mode) | ConvertAccessModeToUnix(access), DEFAULT_FILEMODE);
- }
- if (fd == -1)
- {
- if (error != NULL)
- *error = COULD_NOT_OPEN;
- return NULL;
- }
- if (result != 0 || *capacity > buf.st_size)
- {
- int result = ftruncate(fd, (off_t)*capacity);
- IL2CPP_ASSERT(result == 0);
- NO_UNUSED_WARNING(result);
- }
- if (ownsFd)
- {
- FileHandle* handle = new FileHandle;
- handle->fd = fd;
- handle->doesNotOwnFd = !ownsFd;
- return handle;
- }
- else
- {
- file->doesNotOwnFd = true;
- return file;
- }
- }
- MemoryMappedFile::MemoryMappedFileHandle MemoryMappedFile::View(FileHandle* mappedFileHandle, int64_t* length, int64_t offset, MemoryMappedFileAccess access, int64_t* actualOffset, MemoryMappedFileError* error)
- {
- IL2CPP_ASSERT(actualOffset != NULL);
- int64_t mmap_offset = 0;
- int64_t eff_size = *length;
- struct stat buf = { 0 };
- fstat(mappedFileHandle->fd, &buf);
- if (offset > buf.st_size || ((eff_size + offset) > buf.st_size && !IsSpecialZeroSizeFile(&buf)))
- {
- if (error != NULL)
- *error = ACCESS_DENIED;
- return NULL;
- }
- /**
- * We use the file size if one of the following conditions is true:
- * -input size is zero
- * -input size is bigger than the file and the file is not a magical zero size file such as /dev/mem.
- */
- if (eff_size == 0)
- eff_size = AlignUpToPageSize(buf.st_size) - offset;
- mmap_offset = AlignDownToPageSize(offset);
- eff_size += (offset - mmap_offset);
- *length = eff_size;
- *actualOffset = mmap_offset;
- int flags = ConvertAccessToMemoryMappedFileFlags(access);
- int prot = ConvertFlagsToProt(flags);
- /* translate the flags */
- int mflags = 0;
- if (flags & MONO_MMAP_PRIVATE)
- mflags |= MAP_PRIVATE;
- if (flags & MONO_MMAP_SHARED)
- mflags |= MAP_SHARED;
- if (flags & MONO_MMAP_FIXED)
- mflags |= MAP_FIXED;
- if (flags & MONO_MMAP_32BIT)
- mflags |= MAP_32BIT;
- void* address = mmap(NULL, eff_size, prot, mflags, mappedFileHandle->fd, mmap_offset);
- if (address == MAP_FAILED)
- {
- if (error != NULL)
- *error = COULD_NOT_MAP_MEMORY;
- return NULL;
- }
- return address;
- }
- void MemoryMappedFile::Flush(MemoryMappedFileHandle memoryMappedFileData, int64_t length)
- {
- if (memoryMappedFileData != NULL)
- {
- int error = msync(memoryMappedFileData, length, MS_SYNC);
- IL2CPP_ASSERT(error == 0);
- NO_UNUSED_WARNING(error);
- }
- }
- bool MemoryMappedFile::UnmapView(MemoryMappedFileHandle memoryMappedFileData, int64_t length)
- {
- int error = munmap(memoryMappedFileData, (size_t)length);
- return error == 0;
- }
- bool MemoryMappedFile::Close(FileHandle* file)
- {
- bool result = true;
- if (!file->doesNotOwnFd)
- {
- int error = 0;
- os::File::Close(file, &error);
- if (error != 0)
- result = false;
- }
- return result;
- }
- void MemoryMappedFile::ConfigureHandleInheritability(FileHandle* file, bool inheritability)
- {
- #if IL2CPP_HAS_CLOSE_EXEC
- int flags = fcntl(file->fd, F_GETFD, 0);
- if (inheritability)
- flags &= ~FD_CLOEXEC;
- else
- flags |= FD_CLOEXEC;
- int result = fcntl(file->fd, F_SETFD, flags);
- IL2CPP_ASSERT(result != -1);
- NO_UNUSED_WARNING(result);
- #endif
- }
- bool MemoryMappedFile::OwnsDuplicatedFileHandle(FileHandle* file)
- {
- return !file->doesNotOwnFd;
- }
- }
- }
- #endif
|