]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umapfile.cpp
ICU-59173.0.1.tar.gz
[apple/icu.git] / icuSources / common / umapfile.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f
A
3/*
4******************************************************************************
5*
57a6839d 6* Copyright (C) 1999-2013, International Business Machines
b75a7d8f
A
7* Corporation and others. All Rights Reserved.
8*
9******************************************************************************/
10
11
12/*----------------------------------------------------------------------------
729e4ab9 13 *
b75a7d8f
A
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 *----------------------------------------------------------------------------*/
57a6839d
A
20/* Defines _XOPEN_SOURCE for access to POSIX functions.
21 * Must be before any other #includes. */
22#include "uposixdefs.h"
46f4442e 23
374ca955 24#include "unicode/putil.h"
b75a7d8f
A
25#include "udatamem.h"
26#include "umapfile.h"
27
b75a7d8f
A
28/* memory-mapping base definitions ------------------------------------------ */
29
729e4ab9 30#if MAP_IMPLEMENTATION==MAP_WIN32
f3c0d7a5 31#ifndef WIN32_LEAN_AND_MEAN
b75a7d8f 32# define WIN32_LEAN_AND_MEAN
f3c0d7a5 33#endif
374ca955 34# define VC_EXTRALEAN
b75a7d8f
A
35# define NOUSER
36# define NOSERVICE
37# define NOIME
38# define NOMCX
39# include <windows.h>
73c04bcf 40# include "cmemory.h"
b75a7d8f
A
41
42 typedef HANDLE MemoryMap;
43
44# define IS_MAP(map) ((map)!=NULL)
729e4ab9 45#elif MAP_IMPLEMENTATION==MAP_POSIX || MAP_IMPLEMENTATION==MAP_390DLL
b75a7d8f
A
46 typedef size_t MemoryMap;
47
48# define IS_MAP(map) ((map)!=0)
49
b75a7d8f
A
50# include <unistd.h>
51# include <sys/mman.h>
52# include <sys/stat.h>
53# include <fcntl.h>
54
55# ifndef MAP_FAILED
56# define MAP_FAILED ((void*)-1)
57# endif
58
729e4ab9 59# if MAP_IMPLEMENTATION==MAP_390DLL
b75a7d8f
A
60 /* No memory mapping for 390 batch mode. Fake it using dll loading. */
61# include <dll.h>
62# include "cstring.h"
63# include "cmemory.h"
64# include "unicode/udata.h"
65# define LIB_PREFIX "lib"
66# define LIB_SUFFIX ".dll"
729e4ab9 67 /* This is inconvienient until we figure out what to do with U_ICUDATA_NAME in utypes.h */
b75a7d8f 68# define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_NAME_STRING "_dat"
b75a7d8f 69# endif
729e4ab9 70#elif MAP_IMPLEMENTATION==MAP_STDIO
73c04bcf 71# include <stdio.h>
b75a7d8f
A
72# include "cmemory.h"
73
74 typedef void *MemoryMap;
75
76# define IS_MAP(map) ((map)!=NULL)
b75a7d8f
A
77#endif
78
b75a7d8f
A
79/*----------------------------------------------------------------------------*
80 * *
81 * Memory Mapped File support. Platform dependent implementation of *
82 * functions used by the rest of the implementation.*
83 * *
84 *----------------------------------------------------------------------------*/
73c04bcf 85#if MAP_IMPLEMENTATION==MAP_NONE
729e4ab9 86 U_CFUNC UBool
73c04bcf
A
87 uprv_mapFile(UDataMemory *pData, const char *path) {
88 UDataMemory_init(pData); /* Clear the output struct. */
89 return FALSE; /* no file access */
90 }
91
729e4ab9 92 U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
73c04bcf
A
93 /* nothing to do */
94 }
95#elif MAP_IMPLEMENTATION==MAP_WIN32
729e4ab9 96 U_CFUNC UBool
b75a7d8f
A
97 uprv_mapFile(
98 UDataMemory *pData, /* Fill in with info on the result doing the mapping. */
99 /* Output only; any original contents are cleared. */
100 const char *path /* File path to be opened/mapped */
101 )
102 {
103 HANDLE map;
104 HANDLE file;
73c04bcf
A
105 SECURITY_ATTRIBUTES mappingAttributes;
106 SECURITY_ATTRIBUTES *mappingAttributesPtr = NULL;
107 SECURITY_DESCRIPTOR securityDesc;
b75a7d8f
A
108
109 UDataMemory_init(pData); /* Clear the output struct. */
110
111 /* open the input file */
f3c0d7a5 112#if U_PLATFORM_HAS_WINUWP_API == 0
46f4442e 113 file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
b75a7d8f
A
114 OPEN_EXISTING,
115 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
f3c0d7a5
A
116#else
117 // First we need to go from char to UTF-16
118 // u_UCharsToChars could work but it requires length.
119 WCHAR utf16Path[MAX_PATH];
120 int32_t i;
121 for (i = 0; i < UPRV_LENGTHOF(utf16Path); i++)
122 {
123 utf16Path[i] = path[i];
124 if (path[i] == '\0')
125 {
126 break;
127 }
128 }
129 if (i >= UPRV_LENGTHOF(utf16Path))
130 {
131 // Ran out of room, unlikely but be safe
132 utf16Path[UPRV_LENGTHOF(utf16Path) - 1] = '\0';
133 }
134
135 // TODO: Is it worth setting extended parameters to specify random access?
136 file = CreateFile2(utf16Path, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, NULL);
137#endif
b75a7d8f
A
138 if(file==INVALID_HANDLE_VALUE) {
139 return FALSE;
140 }
141
73c04bcf
A
142 /* Declare and initialize a security descriptor.
143 This is required for multiuser systems on Windows 2000 SP4 and beyond */
f3c0d7a5
A
144 // TODO: UWP does not have this function and I do not think it is required?
145#if U_PLATFORM_HAS_WINUWP_API == 0
73c04bcf 146 if (InitializeSecurityDescriptor(&securityDesc, SECURITY_DESCRIPTOR_REVISION)) {
f3c0d7a5 147 /* give the security descriptor a Null Dacl done using the "TRUE, (PACL)NULL" here */
73c04bcf
A
148 if (SetSecurityDescriptorDacl(&securityDesc, TRUE, (PACL)NULL, FALSE)) {
149 /* Make the security attributes point to the security descriptor */
150 uprv_memset(&mappingAttributes, 0, sizeof(mappingAttributes));
151 mappingAttributes.nLength = sizeof(mappingAttributes);
152 mappingAttributes.lpSecurityDescriptor = &securityDesc;
153 mappingAttributes.bInheritHandle = FALSE; /* object uninheritable */
154 mappingAttributesPtr = &mappingAttributes;
155 }
156 }
157 /* else creating security descriptors can fail when we are on Windows 98,
158 and mappingAttributesPtr == NULL for that case. */
159
b75a7d8f 160 /* create an unnamed Windows file-mapping object for the specified file */
73c04bcf 161 map=CreateFileMapping(file, mappingAttributesPtr, PAGE_READONLY, 0, 0, NULL);
f3c0d7a5
A
162#else
163 map = CreateFileMappingFromApp(file, NULL, PAGE_READONLY, 0, NULL);
164#endif
b75a7d8f
A
165 CloseHandle(file);
166 if(map==NULL) {
167 return FALSE;
168 }
169
170 /* map a view of the file into our address space */
171 pData->pHeader=(const DataHeader *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
172 if(pData->pHeader==NULL) {
173 CloseHandle(map);
174 return FALSE;
175 }
176 pData->map=map;
177 return TRUE;
178 }
179
729e4ab9 180 U_CFUNC void
b75a7d8f
A
181 uprv_unmapFile(UDataMemory *pData) {
182 if(pData!=NULL && pData->map!=NULL) {
183 UnmapViewOfFile(pData->pHeader);
184 CloseHandle(pData->map);
185 pData->pHeader=NULL;
186 pData->map=NULL;
187 }
188 }
189
190
191
192#elif MAP_IMPLEMENTATION==MAP_POSIX
729e4ab9 193 U_CFUNC UBool
b75a7d8f
A
194 uprv_mapFile(UDataMemory *pData, const char *path) {
195 int fd;
196 int length;
197 struct stat mystat;
198 void *data;
199
200 UDataMemory_init(pData); /* Clear the output struct. */
201
202 /* determine the length of the file */
203 if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
204 return FALSE;
205 }
206 length=mystat.st_size;
207
208 /* open the file */
209 fd=open(path, O_RDONLY);
210 if(fd==-1) {
211 return FALSE;
212 }
213
214 /* get a view of the mapping */
4388f060 215#if U_PLATFORM != U_PF_HPUX
b75a7d8f
A
216 data=mmap(0, length, PROT_READ, MAP_SHARED, fd, 0);
217#else
218 data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
219#endif
220 close(fd); /* no longer needed */
221 if(data==MAP_FAILED) {
222 return FALSE;
223 }
224
225 pData->map = (char *)data + length;
226 pData->pHeader=(const DataHeader *)data;
227 pData->mapAddr = data;
4388f060 228#if U_PLATFORM == U_PF_IPHONE
729e4ab9 229 posix_madvise(data, length, POSIX_MADV_RANDOM);
46f4442e 230#endif
b75a7d8f
A
231 return TRUE;
232 }
233
729e4ab9 234 U_CFUNC void
b75a7d8f
A
235 uprv_unmapFile(UDataMemory *pData) {
236 if(pData!=NULL && pData->map!=NULL) {
237 size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
238 if(munmap(pData->mapAddr, dataLen)==-1) {
239 }
240 pData->pHeader=NULL;
241 pData->map=0;
242 pData->mapAddr=NULL;
243 }
244 }
245
246
247
73c04bcf
A
248#elif MAP_IMPLEMENTATION==MAP_STDIO
249 /* copy of the filestrm.c/T_FileStream_size() implementation */
250 static int32_t
251 umap_fsize(FILE *f) {
252 int32_t savedPos = ftell(f);
253 int32_t size = 0;
254
255 /*Changes by Bertrand A. D. doesn't affect the current position
256 goes to the end of the file before ftell*/
257 fseek(f, 0, SEEK_END);
258 size = (int32_t)ftell(f);
259 fseek(f, savedPos, SEEK_SET);
260 return size;
261 }
262
729e4ab9 263 U_CFUNC UBool
b75a7d8f 264 uprv_mapFile(UDataMemory *pData, const char *path) {
73c04bcf 265 FILE *file;
b75a7d8f
A
266 int32_t fileLength;
267 void *p;
268
269 UDataMemory_init(pData); /* Clear the output struct. */
270 /* open the input file */
73c04bcf 271 file=fopen(path, "rb");
b75a7d8f
A
272 if(file==NULL) {
273 return FALSE;
274 }
275
276 /* get the file length */
73c04bcf
A
277 fileLength=umap_fsize(file);
278 if(ferror(file) || fileLength<=20) {
279 fclose(file);
b75a7d8f
A
280 return FALSE;
281 }
282
283 /* allocate the memory to hold the file data */
284 p=uprv_malloc(fileLength);
285 if(p==NULL) {
73c04bcf 286 fclose(file);
b75a7d8f
A
287 return FALSE;
288 }
289
290 /* read the file */
73c04bcf 291 if(fileLength!=fread(p, 1, fileLength, file)) {
b75a7d8f 292 uprv_free(p);
73c04bcf 293 fclose(file);
b75a7d8f
A
294 return FALSE;
295 }
296
73c04bcf 297 fclose(file);
b75a7d8f
A
298 pData->map=p;
299 pData->pHeader=(const DataHeader *)p;
300 pData->mapAddr=p;
301 return TRUE;
302 }
303
729e4ab9 304 U_CFUNC void
b75a7d8f
A
305 uprv_unmapFile(UDataMemory *pData) {
306 if(pData!=NULL && pData->map!=NULL) {
307 uprv_free(pData->map);
308 pData->map = NULL;
309 pData->mapAddr = NULL;
310 pData->pHeader = NULL;
311 }
312 }
313
314
315#elif MAP_IMPLEMENTATION==MAP_390DLL
316 /* 390 specific Library Loading.
317 * This is the only platform left that dynamically loads an ICU Data Library.
318 * All other platforms use .data files when dynamic loading is required, but
319 * this turn out to be awkward to support in 390 batch mode.
320 *
321 * The idea here is to hide the fact that 390 is using dll loading from the
322 * rest of ICU, and make it look like there is file loading happening.
323 *
324 */
325
326 static char *strcpy_returnEnd(char *dest, const char *src)
327 {
328 while((*dest=*src)!=0) {
329 ++dest;
330 ++src;
331 }
332 return dest;
333 }
334
335 /*------------------------------------------------------------------------------
336 *
337 * computeDirPath given a user-supplied path of an item to be opened,
338 * compute and return
339 * - the full directory path to be used
340 * when opening the file.
341 * - Pointer to null at end of above returned path
342 *
343 * Parameters:
344 * path: input path. Buffer is not altered.
345 * pathBuffer: Output buffer. Any contents are overwritten.
346 *
347 * Returns:
348 * Pointer to null termination in returned pathBuffer.
349 *
350 * TODO: This works the way ICU historically has, but the
351 * whole data fallback search path is so complicated that
352 * proabably almost no one will ever really understand it,
353 * the potential for confusion is large. (It's not just
354 * this one function, but the whole scheme.)
355 *
356 *------------------------------------------------------------------------------*/
357 static char *uprv_computeDirPath(const char *path, char *pathBuffer)
358 {
359 char *finalSlash; /* Ptr to last dir separator in input path, or null if none. */
360 int32_t pathLen; /* Length of the returned directory path */
361
362 finalSlash = 0;
363 if (path != 0) {
364 finalSlash = uprv_strrchr(path, U_FILE_SEP_CHAR);
365 }
366
367 *pathBuffer = 0;
368 if (finalSlash == 0) {
369 /* No user-supplied path.
370 * Copy the ICU_DATA path to the path buffer and return that*/
371 const char *icuDataDir;
372 icuDataDir=u_getDataDirectory();
373 if(icuDataDir!=NULL && *icuDataDir!=0) {
374 return strcpy_returnEnd(pathBuffer, icuDataDir);
375 } else {
376 /* there is no icuDataDir either. Just return the empty pathBuffer. */
377 return pathBuffer;
378 }
379 }
380
381 /* User supplied path did contain a directory portion.
382 * Copy it to the output path buffer */
383 pathLen = (int32_t)(finalSlash - path + 1);
384 uprv_memcpy(pathBuffer, path, pathLen);
385 *(pathBuffer+pathLen) = 0;
386 return pathBuffer+pathLen;
387 }
388
389
390# define DATA_TYPE "dat"
391
729e4ab9 392 U_CFUNC UBool uprv_mapFile(UDataMemory *pData, const char *path) {
b75a7d8f
A
393 const char *inBasename;
394 char *basename;
395 char pathBuffer[1024];
396 const DataHeader *pHeader;
397 dllhandle *handle;
398 void *val=0;
399
400 inBasename=uprv_strrchr(path, U_FILE_SEP_CHAR);
401 if(inBasename==NULL) {
402 inBasename = path;
403 } else {
404 inBasename++;
405 }
406 basename=uprv_computeDirPath(path, pathBuffer);
407 if(uprv_strcmp(inBasename, U_ICUDATA_NAME".dat") != 0) {
408 /* must mmap file... for build */
409 int fd;
410 int length;
411 struct stat mystat;
412 void *data;
413 UDataMemory_init(pData); /* Clear the output struct. */
414
415 /* determine the length of the file */
416 if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
417 return FALSE;
418 }
419 length=mystat.st_size;
420
421 /* open the file */
422 fd=open(path, O_RDONLY);
423 if(fd==-1) {
424 return FALSE;
425 }
426
427 /* get a view of the mapping */
428 data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
429 close(fd); /* no longer needed */
430 if(data==MAP_FAILED) {
431 return FALSE;
432 }
433 pData->map = (char *)data + length;
434 pData->pHeader=(const DataHeader *)data;
435 pData->mapAddr = data;
436 return TRUE;
437 }
438
439# ifdef OS390BATCH
440 /* ### hack: we still need to get u_getDataDirectory() fixed
441 for OS/390 (batch mode - always return "//"? )
442 and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!)
443 This is probably due to the strange file system on OS/390. It's more like
444 a database with short entry names than a typical file system. */
445 /* U_ICUDATA_NAME should always have the correct name */
446 /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */
447 /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */
448 /* PROJECT!!!!! */
449 uprv_strcpy(pathBuffer, "IXMI" U_ICU_VERSION_SHORT "DA");
450# else
451 /* set up the library name */
452 uprv_strcpy(basename, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX);
453# endif
454
455# ifdef UDATA_DEBUG
456 fprintf(stderr, "dllload: %s ", pathBuffer);
457# endif
458
459 handle=dllload(pathBuffer);
460
461# ifdef UDATA_DEBUG
462 fprintf(stderr, " -> %08X\n", handle );
463# endif
464
465 if(handle != NULL) {
466 /* we have a data DLL - what kind of lookup do we need here? */
467 /* try to find the Table of Contents */
468 UDataMemory_init(pData); /* Clear the output struct. */
469 val=dllqueryvar((dllhandle*)handle, U_ICUDATA_ENTRY_NAME);
470 if(val == 0) {
471 /* failed... so keep looking */
472 return FALSE;
473 }
474# ifdef UDATA_DEBUG
475 fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", handle, U_ICUDATA_ENTRY_NAME, val);
476# endif
477
478 pData->pHeader=(const DataHeader *)val;
479 return TRUE;
480 } else {
481 return FALSE; /* no handle */
482 }
483 }
484
729e4ab9 485 U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
b75a7d8f
A
486 if(pData!=NULL && pData->map!=NULL) {
487 uprv_free(pData->map);
488 pData->map = NULL;
489 pData->mapAddr = NULL;
490 pData->pHeader = NULL;
491 }
492 }
493
494#else
495# error MAP_IMPLEMENTATION is set incorrectly
496#endif