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 462