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