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