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