• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
uprv_mapFile(UDataMemory * pData,const char * path)80     uprv_mapFile(UDataMemory *pData, const char *path) {
81         UDataMemory_init(pData); /* Clear the output struct. */
82         return FALSE;            /* no file access */
83     }
84 
uprv_unmapFile(UDataMemory * pData)85     U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
86         /* nothing to do */
87     }
88 #elif MAP_IMPLEMENTATION==MAP_WIN32
89     U_CFUNC UBool
uprv_mapFile(UDataMemory * pData,const char * path)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
uprv_unmapFile(UDataMemory * pData)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
uprv_mapFile(UDataMemory * pData,const char * path)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
uprv_unmapFile(UDataMemory * pData)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
umap_fsize(FILE * f)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
uprv_mapFile(UDataMemory * pData,const char * path)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
uprv_unmapFile(UDataMemory * pData)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 
strcpy_returnEnd(char * dest,const char * src)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      *------------------------------------------------------------------------------*/
uprv_computeDirPath(const char * path,char * pathBuffer)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 
uprv_mapFile(UDataMemory * pData,const char * path)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 
uprv_unmapFile(UDataMemory * pData)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
462