/src/icu/icu4c/source/common/umapfile.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // © 2016 and later: Unicode, Inc. and others. |
2 | | // License & terms of use: http://www.unicode.org/copyright.html |
3 | | /* |
4 | | ****************************************************************************** |
5 | | * |
6 | | * Copyright (C) 1999-2013, International Business Machines |
7 | | * Corporation and others. All Rights Reserved. |
8 | | * |
9 | | ******************************************************************************/ |
10 | | |
11 | | |
12 | | /*---------------------------------------------------------------------------- |
13 | | * |
14 | | * Memory mapped file wrappers for use by the ICU Data Implementation |
15 | | * All of the platform-specific implementation for mapping data files |
16 | | * is here. The rest of the ICU Data implementation uses only the |
17 | | * wrapper functions. |
18 | | * |
19 | | *----------------------------------------------------------------------------*/ |
20 | | /* Defines _XOPEN_SOURCE for access to POSIX functions. |
21 | | * Must be before any other #includes. */ |
22 | | #include "uposixdefs.h" |
23 | | |
24 | | #include "unicode/putil.h" |
25 | | #include "unicode/ustring.h" |
26 | | #include "udatamem.h" |
27 | | #include "umapfile.h" |
28 | | |
29 | | /* memory-mapping base definitions ------------------------------------------ */ |
30 | | |
31 | | #if MAP_IMPLEMENTATION==MAP_WIN32 |
32 | | #ifndef WIN32_LEAN_AND_MEAN |
33 | | # define WIN32_LEAN_AND_MEAN |
34 | | #endif |
35 | | # define VC_EXTRALEAN |
36 | | # define NOUSER |
37 | | # define NOSERVICE |
38 | | # define NOIME |
39 | | # define NOMCX |
40 | | |
41 | | # if U_PLATFORM_HAS_WINUWP_API == 1 |
42 | | // Some previous versions of the Windows 10 SDK don't expose various APIs for UWP applications |
43 | | // to use, even though UWP apps are allowed to call and use them. Temporarily change the |
44 | | // WINAPI family partition below to Desktop, so that function declarations are visible for UWP. |
45 | | # include <winapifamily.h> |
46 | | # if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)) |
47 | | # pragma push_macro("WINAPI_PARTITION_DESKTOP") |
48 | | # undef WINAPI_PARTITION_DESKTOP |
49 | | # define WINAPI_PARTITION_DESKTOP 1 |
50 | | # define CHANGED_WINAPI_PARTITION_DESKTOP_VALUE |
51 | | # endif |
52 | | # endif |
53 | | |
54 | | # include <windows.h> |
55 | | |
56 | | # if U_PLATFORM_HAS_WINUWP_API == 1 && defined(CHANGED_WINAPI_PARTITION_DESKTOP_VALUE) |
57 | | # pragma pop_macro("WINAPI_PARTITION_DESKTOP") |
58 | | # endif |
59 | | |
60 | | # include "cmemory.h" |
61 | | |
62 | | typedef HANDLE MemoryMap; |
63 | | |
64 | | # define IS_MAP(map) ((map)!=nullptr) |
65 | | |
66 | | #elif MAP_IMPLEMENTATION==MAP_POSIX |
67 | | typedef size_t MemoryMap; |
68 | | |
69 | | # define IS_MAP(map) ((map)!=0) |
70 | | |
71 | | # include <unistd.h> |
72 | | # include <sys/mman.h> |
73 | | # include <sys/stat.h> |
74 | | # include <fcntl.h> |
75 | | |
76 | | # ifndef MAP_FAILED |
77 | | # define MAP_FAILED ((void*)-1) |
78 | | # endif |
79 | | #elif MAP_IMPLEMENTATION==MAP_STDIO |
80 | | # include <stdio.h> |
81 | | # include "cmemory.h" |
82 | | |
83 | | typedef void *MemoryMap; |
84 | | |
85 | | # define IS_MAP(map) ((map)!=nullptr) |
86 | | #endif |
87 | | |
88 | | /*----------------------------------------------------------------------------* |
89 | | * * |
90 | | * Memory Mapped File support. Platform dependent implementation of * |
91 | | * functions used by the rest of the implementation.* |
92 | | * * |
93 | | *----------------------------------------------------------------------------*/ |
94 | | #if MAP_IMPLEMENTATION==MAP_NONE |
95 | | U_CFUNC UBool |
96 | | uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) { |
97 | | if (U_FAILURE(*status)) { |
98 | | return false; |
99 | | } |
100 | | UDataMemory_init(pData); /* Clear the output struct. */ |
101 | | return false; /* no file access */ |
102 | | } |
103 | | |
104 | | U_CFUNC void uprv_unmapFile(UDataMemory *pData) { |
105 | | /* nothing to do */ |
106 | | } |
107 | | #elif MAP_IMPLEMENTATION==MAP_WIN32 |
108 | | U_CFUNC UBool |
109 | | uprv_mapFile( |
110 | | UDataMemory *pData, /* Fill in with info on the result doing the mapping. */ |
111 | | /* Output only; any original contents are cleared. */ |
112 | | const char *path, /* File path to be opened/mapped. */ |
113 | | UErrorCode *status /* Error status, used to report out-of-memory errors. */ |
114 | | ) |
115 | | { |
116 | | if (U_FAILURE(*status)) { |
117 | | return false; |
118 | | } |
119 | | |
120 | | HANDLE map = nullptr; |
121 | | HANDLE file = INVALID_HANDLE_VALUE; |
122 | | |
123 | | UDataMemory_init(pData); /* Clear the output struct. */ |
124 | | |
125 | | /* open the input file */ |
126 | | #if U_PLATFORM_HAS_WINUWP_API == 0 |
127 | | // Note: In the non-UWP code-path (ie: Win32), the value of the path variable might have come from |
128 | | // the CRT 'getenv' function, and would be therefore be encoded in the default ANSI code page. |
129 | | // This means that we can't call the *W version of API below, whereas in the UWP code-path |
130 | | // there is no 'getenv' call, and thus the string will be only UTF-8/Invariant characters. |
131 | | file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr, |
132 | | OPEN_EXISTING, |
133 | | FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, nullptr); |
134 | | #else |
135 | | // Convert from UTF-8 string to UTF-16 string. |
136 | | wchar_t utf16Path[MAX_PATH]; |
137 | | int32_t pathUtf16Len = 0; |
138 | | u_strFromUTF8(reinterpret_cast<char16_t*>(utf16Path), static_cast<int32_t>(UPRV_LENGTHOF(utf16Path)), &pathUtf16Len, path, -1, status); |
139 | | |
140 | | if (U_FAILURE(*status)) { |
141 | | return false; |
142 | | } |
143 | | if (*status == U_STRING_NOT_TERMINATED_WARNING) { |
144 | | // Report back an error instead of a warning. |
145 | | *status = U_BUFFER_OVERFLOW_ERROR; |
146 | | return false; |
147 | | } |
148 | | |
149 | | file = CreateFileW(utf16Path, GENERIC_READ, FILE_SHARE_READ, nullptr, |
150 | | OPEN_EXISTING, |
151 | | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr); |
152 | | #endif |
153 | | if (file == INVALID_HANDLE_VALUE) { |
154 | | // If we failed to open the file due to an out-of-memory error, then we want |
155 | | // to report that error back to the caller. |
156 | | if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) { |
157 | | *status = U_MEMORY_ALLOCATION_ERROR; |
158 | | } |
159 | | return false; |
160 | | } |
161 | | |
162 | | // Note: We use nullptr/nullptr for lpAttributes parameter below. |
163 | | // This means our handle cannot be inherited and we will get the default security descriptor. |
164 | | /* create an unnamed Windows file-mapping object for the specified file */ |
165 | | map = CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0, nullptr); |
166 | | |
167 | | CloseHandle(file); |
168 | | if (map == nullptr) { |
169 | | // If we failed to create the mapping due to an out-of-memory error, then |
170 | | // we want to report that error back to the caller. |
171 | | if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) { |
172 | | *status = U_MEMORY_ALLOCATION_ERROR; |
173 | | } |
174 | | return false; |
175 | | } |
176 | | |
177 | | /* map a view of the file into our address space */ |
178 | | pData->pHeader = reinterpret_cast<const DataHeader *>(MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0)); |
179 | | if (pData->pHeader == nullptr) { |
180 | | CloseHandle(map); |
181 | | return false; |
182 | | } |
183 | | pData->map = map; |
184 | | return true; |
185 | | } |
186 | | |
187 | | U_CFUNC void |
188 | | uprv_unmapFile(UDataMemory *pData) { |
189 | | if (pData != nullptr && pData->map != nullptr) { |
190 | | UnmapViewOfFile(pData->pHeader); |
191 | | CloseHandle(pData->map); |
192 | | pData->pHeader = nullptr; |
193 | | pData->map = nullptr; |
194 | | } |
195 | | } |
196 | | |
197 | | |
198 | | |
199 | | #elif MAP_IMPLEMENTATION==MAP_POSIX |
200 | | U_CFUNC UBool |
201 | 0 | uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) { |
202 | 0 | int fd; |
203 | 0 | int length; |
204 | 0 | struct stat mystat; |
205 | 0 | void *data; |
206 | |
|
207 | 0 | if (U_FAILURE(*status)) { |
208 | 0 | return false; |
209 | 0 | } |
210 | | |
211 | 0 | UDataMemory_init(pData); /* Clear the output struct. */ |
212 | | |
213 | | /* determine the length of the file */ |
214 | 0 | if(stat(path, &mystat)!=0 || mystat.st_size<=0) { |
215 | 0 | return false; |
216 | 0 | } |
217 | 0 | length=mystat.st_size; |
218 | | |
219 | | /* open the file */ |
220 | 0 | fd=open(path, O_RDONLY); |
221 | 0 | if(fd==-1) { |
222 | 0 | return false; |
223 | 0 | } |
224 | | |
225 | | /* get a view of the mapping */ |
226 | 0 | #if U_PLATFORM != U_PF_HPUX |
227 | 0 | data=mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, 0); |
228 | | #else |
229 | | data=mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0); |
230 | | #endif |
231 | 0 | close(fd); /* no longer needed */ |
232 | 0 | if(data==MAP_FAILED) { |
233 | | // Possibly check the errno value for ENOMEM, and report U_MEMORY_ALLOCATION_ERROR? |
234 | 0 | return false; |
235 | 0 | } |
236 | | |
237 | 0 | pData->map = (char *)data + length; |
238 | 0 | pData->pHeader=(const DataHeader *)data; |
239 | 0 | pData->mapAddr = data; |
240 | | #if U_PLATFORM == U_PF_IPHONE || U_PLATFORM == U_PF_ANDROID |
241 | | // Apparently supported from Android 23 and higher: |
242 | | // https://github.com/ggml-org/llama.cpp/pull/3631 |
243 | | // Checking for the flag itself is safer than checking for __ANDROID_API__. |
244 | | # ifdef POSIX_MADV_RANDOM |
245 | | posix_madvise(data, length, POSIX_MADV_RANDOM); |
246 | | # endif |
247 | | #endif |
248 | 0 | return true; |
249 | 0 | } |
250 | | |
251 | | U_CFUNC void |
252 | 0 | uprv_unmapFile(UDataMemory *pData) { |
253 | 0 | if(pData!=nullptr && pData->map!=nullptr) { |
254 | 0 | size_t dataLen = (char *)pData->map - (char *)pData->mapAddr; |
255 | 0 | if(munmap(pData->mapAddr, dataLen)==-1) { |
256 | 0 | } |
257 | 0 | pData->pHeader=nullptr; |
258 | 0 | pData->map=nullptr; |
259 | 0 | pData->mapAddr=nullptr; |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | | |
264 | | |
265 | | #elif MAP_IMPLEMENTATION==MAP_STDIO |
266 | | /* copy of the filestrm.c/T_FileStream_size() implementation */ |
267 | | static int32_t |
268 | | umap_fsize(FILE *f) { |
269 | | int32_t savedPos = ftell(f); |
270 | | int32_t size = 0; |
271 | | |
272 | | /*Changes by Bertrand A. D. doesn't affect the current position |
273 | | goes to the end of the file before ftell*/ |
274 | | fseek(f, 0, SEEK_END); |
275 | | size = (int32_t)ftell(f); |
276 | | fseek(f, savedPos, SEEK_SET); |
277 | | return size; |
278 | | } |
279 | | |
280 | | U_CFUNC UBool |
281 | | uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) { |
282 | | FILE *file; |
283 | | int32_t fileLength; |
284 | | void *p; |
285 | | |
286 | | if (U_FAILURE(*status)) { |
287 | | return false; |
288 | | } |
289 | | |
290 | | UDataMemory_init(pData); /* Clear the output struct. */ |
291 | | /* open the input file */ |
292 | | file=fopen(path, "rb"); |
293 | | if(file==nullptr) { |
294 | | return false; |
295 | | } |
296 | | |
297 | | /* get the file length */ |
298 | | fileLength=umap_fsize(file); |
299 | | if(ferror(file) || fileLength<=20) { |
300 | | fclose(file); |
301 | | return false; |
302 | | } |
303 | | |
304 | | /* allocate the memory to hold the file data */ |
305 | | p=uprv_malloc(fileLength); |
306 | | if(p==nullptr) { |
307 | | fclose(file); |
308 | | *status = U_MEMORY_ALLOCATION_ERROR; |
309 | | return false; |
310 | | } |
311 | | |
312 | | /* read the file */ |
313 | | if(fileLength!=fread(p, 1, fileLength, file)) { |
314 | | uprv_free(p); |
315 | | fclose(file); |
316 | | return false; |
317 | | } |
318 | | |
319 | | fclose(file); |
320 | | pData->map=p; |
321 | | pData->pHeader=(const DataHeader *)p; |
322 | | pData->mapAddr=p; |
323 | | return true; |
324 | | } |
325 | | |
326 | | U_CFUNC void |
327 | | uprv_unmapFile(UDataMemory *pData) { |
328 | | if(pData!=nullptr && pData->map!=nullptr) { |
329 | | uprv_free(pData->map); |
330 | | pData->map = nullptr; |
331 | | pData->mapAddr = nullptr; |
332 | | pData->pHeader = nullptr; |
333 | | } |
334 | | } |
335 | | #else |
336 | | # error MAP_IMPLEMENTATION is set incorrectly |
337 | | #endif |