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