From fe12e079bb3991a5fcd3745a4d44406533e0e25e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 25 Nov 2017 17:38:37 +0100 Subject: [PATCH] Reimplement NBIO windows mmap --- libretro-common/file/nbio/nbio_windowsmmap.c | 210 ++++++------------- 1 file changed, 64 insertions(+), 146 deletions(-) diff --git a/libretro-common/file/nbio/nbio_windowsmmap.c b/libretro-common/file/nbio/nbio_windowsmmap.c index 58329ad078..350b6a5275 100644 --- a/libretro-common/file/nbio/nbio_windowsmmap.c +++ b/libretro-common/file/nbio/nbio_windowsmmap.c @@ -28,6 +28,8 @@ #include #include +#include + /* Assume W-functions do not work below VC2005 and Xbox platforms */ #if defined(_MSC_VER) && _MSC_VER < 1400 || defined(_XBOX) @@ -37,180 +39,110 @@ #endif +#ifndef FILE_SHARE_ALL +#define FILE_SHARE_ALL (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE) +#endif + struct nbio_t { - FILE* f; - void* data; - size_t progress; + HANDLE file; + bool is_write; size_t len; - /* - * possible values: - * NBIO_READ, NBIO_WRITE - obvious - * -1 - currently doing nothing - * -2 - the pointer was reallocated since the last operation - */ - signed char op; - signed char mode; + void* ptr; }; -#if !defined(_WIN32) || defined(LEGACY_WIN32) -static const char * modes[]={ "rb", "wb", "r+b", "rb", "wb", "r+b" }; -#else -static const wchar_t * modes[]={ L"rb", L"wb", L"r+b", L"rb", L"wb", L"r+b" }; -#endif - static struct nbio_t* nbio_mmap_win32_open(const char * filename, unsigned mode) { - void *buf = NULL; - struct nbio_t* handle = NULL; - size_t len = 0; + static const DWORD dispositions[] = { OPEN_EXISTING, CREATE_ALWAYS, OPEN_ALWAYS, OPEN_EXISTING, CREATE_ALWAYS }; + HANDLE mem; + LARGE_INTEGER len; + struct nbio_t* handle = NULL; + void* ptr = NULL; + bool is_write = (mode == NBIO_WRITE || mode == NBIO_UPDATE || mode == BIO_WRITE); + DWORD access = (is_write ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ); #if !defined(_WIN32) || defined(LEGACY_WIN32) - FILE* f = fopen(filename, modes[mode]); + HANDLE file = CreateFile(filename, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL); #else wchar_t *filename_wide = utf8_to_utf16_string_alloc(filename); - FILE* f = _wfopen(filename_wide, modes[mode]); + HANDLE file = CreateFileW(filename_wide, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL); if (filename_wide) free(filename_wide); #endif - if (!f) + + if (file == INVALID_HANDLE_VALUE) return NULL; - handle = (struct nbio_t*)malloc(sizeof(struct nbio_t)); + GetFileSizeEx(file, &len); - if (!handle) - goto error; + mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL); + ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len.QuadPart); + CloseHandle(mem); - handle->f = f; + handle = malloc(sizeof(struct nbio_t)); - switch (mode) - { - case NBIO_WRITE: - case BIO_WRITE: - break; - default: - fseek(handle->f, 0, SEEK_END); - len = ftell(handle->f); - break; - } - - handle->mode = mode; - - if (len) - buf = malloc(len); - - if (len && !buf) - goto error; - - handle->data = buf; - handle->len = len; - handle->progress = handle->len; - handle->op = -2; + handle->file = file; + handle->is_write = is_write; + handle->len = len.QuadPart; + handle->ptr = ptr; return handle; - -error: - if (handle) - free(handle); - fclose(f); - return NULL; } static void nbio_mmap_win32_begin_read(struct nbio_t* handle) { - if (!handle) - return; - - if (handle->op >= 0) - { - puts("ERROR - attempted file read operation while busy"); - abort(); - } - - fseek(handle->f, 0, SEEK_SET); - - handle->op = NBIO_READ; - handle->progress = 0; + /* not needed */ } static void nbio_mmap_win32_begin_write(struct nbio_t* handle) { - if (!handle) - return; - - if (handle->op >= 0) - { - puts("ERROR - attempted file write operation while busy"); - abort(); - } - - fseek(handle->f, 0, SEEK_SET); - handle->op = NBIO_WRITE; - handle->progress = 0; + /* not needed */ } static bool nbio_mmap_win32_iterate(struct nbio_t* handle) { - size_t amount = 65536; - - if (!handle) - return false; - - if (amount > handle->len - handle->progress) - amount = handle->len - handle->progress; - - switch (handle->op) - { - case NBIO_READ: - if (handle->mode == BIO_READ) - { - amount = handle->len; - fread((char*)handle->data, 1, amount, handle->f); - } - else - fread((char*)handle->data + handle->progress, 1, amount, handle->f); - break; - case NBIO_WRITE: - if (handle->mode == BIO_WRITE) - { - size_t written = 0; - amount = handle->len; - written = fwrite((char*)handle->data, 1, amount, handle->f); - if (written != amount) - return false; - } - else - fwrite((char*)handle->data + handle->progress, 1, amount, handle->f); - break; - } - - handle->progress += amount; - - if (handle->progress == handle->len) - handle->op = -1; - return (handle->op < 0); + /* not needed */ + return true; } static void nbio_mmap_win32_resize(struct nbio_t* handle, size_t len) { + LARGE_INTEGER len_li; + HANDLE mem; + if (!handle) return; - if (handle->op >= 0) - { - puts("ERROR - attempted file resize operation while busy"); - abort(); - } if (len < handle->len) { + /* this works perfectly fine if this check is removed, + * but it won't work on other nbio implementations */ + /* therefore, it's blocked so nobody accidentally + * relies on it. */ puts("ERROR - attempted file shrink operation, not implemented"); abort(); } - handle->len = len; - handle->data = realloc(handle->data, handle->len); - handle->op = -1; - handle->progress = handle->len; + len_li.QuadPart = len; + SetFilePointerEx(handle->file, len_li, NULL, FILE_BEGIN); + + if (!SetEndOfFile(handle->file)) + { + puts("ERROR - couldn't resize file (SetEndOfFile)"); + abort(); /* this one returns void and I can't find any other way for it to report failure */ + } + handle->len = len; + + UnmapViewOfFile(handle->ptr); + mem = CreateFileMapping(handle->file, NULL, handle->is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL); + handle->ptr = MapViewOfFile(mem, handle->is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len); + CloseHandle(mem); + + if (!handle->ptr) + { + puts("ERROR - couldn't resize file (MapViewOfFile)"); + abort(); + } } static void *nbio_mmap_win32_get_ptr(struct nbio_t* handle, size_t* len) @@ -219,34 +151,20 @@ static void *nbio_mmap_win32_get_ptr(struct nbio_t* handle, size_t* len) return NULL; if (len) *len = handle->len; - if (handle->op == -1) - return handle->data; - return NULL; + return handle->ptr; } static void nbio_mmap_win32_cancel(struct nbio_t* handle) { - if (!handle) - return; - - handle->op = -1; - handle->progress = handle->len; + /* not needed */ } static void nbio_mmap_win32_free(struct nbio_t* handle) { if (!handle) return; - if (handle->op >= 0) - { - puts("ERROR - attempted free() while busy"); - abort(); - } - fclose(handle->f); - free(handle->data); - - handle->f = NULL; - handle->data = NULL; + CloseHandle(handle->file); + UnmapViewOfFile(handle->ptr); free(handle); }