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