1 /* Copyright (C) 2010-2018 The RetroArch team
2 *
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (nbio_windowsmmap.c).
5 * ---------------------------------------------------------------------------------------
6 *
7 * Permission is hereby granted, free of charge,
8 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #include <file/nbio.h>
24
25 #if defined(_WIN32) && !defined(_XBOX)
26
27 #include <stdio.h>
28 #include <stdlib.h>
29
30 #include <encodings/utf.h>
31
32 #include <windows.h>
33
34 /* Assume W-functions do not work below Win2K and Xbox platforms */
35 #if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
36
37 #ifndef LEGACY_WIN32
38 #define LEGACY_WIN32
39 #endif
40
41 #endif
42
43 #ifndef FILE_SHARE_ALL
44 #define FILE_SHARE_ALL (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)
45 #endif
46
47 struct nbio_mmap_win32_t
48 {
49 HANDLE file;
50 bool is_write;
51 size_t len;
52 void* ptr;
53 };
54
nbio_mmap_win32_open(const char * filename,unsigned mode)55 static void *nbio_mmap_win32_open(const char * filename, unsigned mode)
56 {
57 static const DWORD dispositions[] = { OPEN_EXISTING, CREATE_ALWAYS, OPEN_ALWAYS, OPEN_EXISTING, CREATE_ALWAYS };
58 HANDLE mem;
59 #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
60 LARGE_INTEGER len;
61 #else
62 SIZE_T len;
63 #endif
64 struct nbio_mmap_win32_t* handle = NULL;
65 void* ptr = NULL;
66 bool is_write = (mode == NBIO_WRITE || mode == NBIO_UPDATE || mode == BIO_WRITE);
67 DWORD access = (is_write ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ);
68 #if !defined(_WIN32) || defined(LEGACY_WIN32)
69 HANDLE file = CreateFile(filename, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
70 #else
71 wchar_t *filename_wide = utf8_to_utf16_string_alloc(filename);
72 #ifdef __WINRT__
73 HANDLE file = CreateFile2(filename_wide, access, FILE_SHARE_ALL, dispositions[mode], NULL);
74 #else
75 HANDLE file = CreateFileW(filename_wide, access, FILE_SHARE_ALL, NULL, dispositions[mode], FILE_ATTRIBUTE_NORMAL, NULL);
76 #endif
77
78 if (filename_wide)
79 free(filename_wide);
80 #endif
81
82 if (file == INVALID_HANDLE_VALUE)
83 return NULL;
84
85 #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
86 /* GetFileSizeEx is new for Windows 2000 */
87 GetFileSizeEx(file, &len);
88 mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
89 ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len.QuadPart);
90 #else
91 GetFileSize(file, &len);
92 mem = CreateFileMapping(file, NULL, is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
93 ptr = MapViewOfFile(mem, is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
94 #endif
95
96 CloseHandle(mem);
97
98 handle = (struct nbio_mmap_win32_t*)malloc(sizeof(struct nbio_mmap_win32_t));
99
100 handle->file = file;
101 handle->is_write = is_write;
102 #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
103 handle->len = len.QuadPart;
104 #else
105 handle->len = len;
106 #endif
107 handle->ptr = ptr;
108
109 return handle;
110 }
111
nbio_mmap_win32_begin_read(void * data)112 static void nbio_mmap_win32_begin_read(void *data)
113 {
114 /* not needed */
115 }
116
nbio_mmap_win32_begin_write(void * data)117 static void nbio_mmap_win32_begin_write(void *data)
118 {
119 /* not needed */
120 }
121
nbio_mmap_win32_iterate(void * data)122 static bool nbio_mmap_win32_iterate(void *data)
123 {
124 /* not needed */
125 return true;
126 }
127
nbio_mmap_win32_resize(void * data,size_t len)128 static void nbio_mmap_win32_resize(void *data, size_t len)
129 {
130 #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
131 LARGE_INTEGER len_li;
132 #else
133 SIZE_T len_li;
134 #endif
135 HANDLE mem;
136 struct nbio_mmap_win32_t* handle = (struct nbio_mmap_win32_t*)data;
137
138 if (!handle)
139 return;
140
141 if (len < handle->len)
142 {
143 /* this works perfectly fine if this check is removed,
144 * but it won't work on other nbio implementations */
145 /* therefore, it's blocked so nobody accidentally
146 * relies on it. */
147 puts("ERROR - attempted file shrink operation, not implemented");
148 abort();
149 }
150
151 #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
152 /* SetFilePointerEx is new for Windows 2000 */
153 len_li.QuadPart = len;
154 SetFilePointerEx(handle->file, len_li, NULL, FILE_BEGIN);
155 #else
156 len_li = len;
157 SetFilePointer(handle->file, len_li, NULL, FILE_BEGIN);
158 #endif
159
160 if (!SetEndOfFile(handle->file))
161 {
162 puts("ERROR - couldn't resize file (SetEndOfFile)");
163 abort(); /* this one returns void and I can't find any other way for it to report failure */
164 }
165 handle->len = len;
166
167 UnmapViewOfFile(handle->ptr);
168 mem = CreateFileMapping(handle->file, NULL, handle->is_write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, NULL);
169 handle->ptr = MapViewOfFile(mem, handle->is_write ? (FILE_MAP_READ|FILE_MAP_WRITE) : FILE_MAP_READ, 0, 0, len);
170 CloseHandle(mem);
171
172 if (!handle->ptr)
173 {
174 puts("ERROR - couldn't resize file (MapViewOfFile)");
175 abort();
176 }
177 }
178
nbio_mmap_win32_get_ptr(void * data,size_t * len)179 static void *nbio_mmap_win32_get_ptr(void *data, size_t* len)
180 {
181 struct nbio_mmap_win32_t* handle = (struct nbio_mmap_win32_t*)data;
182 if (!handle)
183 return NULL;
184 if (len)
185 *len = handle->len;
186 return handle->ptr;
187 }
188
nbio_mmap_win32_cancel(void * data)189 static void nbio_mmap_win32_cancel(void *data)
190 {
191 /* not needed */
192 }
193
nbio_mmap_win32_free(void * data)194 static void nbio_mmap_win32_free(void *data)
195 {
196 struct nbio_mmap_win32_t* handle = (struct nbio_mmap_win32_t*)data;
197 if (!handle)
198 return;
199 CloseHandle(handle->file);
200 UnmapViewOfFile(handle->ptr);
201 free(handle);
202 }
203
204 nbio_intf_t nbio_mmap_win32 = {
205 nbio_mmap_win32_open,
206 nbio_mmap_win32_begin_read,
207 nbio_mmap_win32_begin_write,
208 nbio_mmap_win32_iterate,
209 nbio_mmap_win32_resize,
210 nbio_mmap_win32_get_ptr,
211 nbio_mmap_win32_cancel,
212 nbio_mmap_win32_free,
213 "nbio_mmap_win32",
214 };
215 #else
216 nbio_intf_t nbio_mmap_win32 = {
217 NULL,
218 NULL,
219 NULL,
220 NULL,
221 NULL,
222 NULL,
223 NULL,
224 NULL,
225 "nbio_mmap_win32",
226 };
227
228 #endif
229