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 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 void uprv_unmapFile(UDataMemory *pData) { 90 /* nothing to do */ 91 } 92 #elif MAP_IMPLEMENTATION==MAP_WIN32 93 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 150 void uprv_unmapFile(UDataMemory * pData)151 uprv_unmapFile(UDataMemory *pData) { 152 if(pData!=NULL && pData->map!=NULL) { 153 UnmapViewOfFile(pData->pHeader); 154 CloseHandle(pData->map); 155 pData->pHeader=NULL; 156 pData->map=NULL; 157 } 158 } 159 160 161 162 #elif MAP_IMPLEMENTATION==MAP_POSIX 163 UBool uprv_mapFile(UDataMemory * pData,const char * path)164 uprv_mapFile(UDataMemory *pData, const char *path) { 165 int fd; 166 int length; 167 struct stat mystat; 168 void *data; 169 170 UDataMemory_init(pData); /* Clear the output struct. */ 171 172 /* determine the length of the file */ 173 if(stat(path, &mystat)!=0 || mystat.st_size<=0) { 174 return FALSE; 175 } 176 length=mystat.st_size; 177 178 /* open the file */ 179 fd=open(path, O_RDONLY); 180 if(fd==-1) { 181 return FALSE; 182 } 183 184 /* get a view of the mapping */ 185 #ifndef U_HPUX 186 data=mmap(0, length, PROT_READ, MAP_SHARED, fd, 0); 187 #else 188 data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0); 189 #endif 190 close(fd); /* no longer needed */ 191 if(data==MAP_FAILED) { 192 return FALSE; 193 } 194 195 pData->map = (char *)data + length; 196 pData->pHeader=(const DataHeader *)data; 197 pData->mapAddr = data; 198 #if defined(U_DARWIN) && TARGET_OS_IPHONE 199 posix_madvise(data, length, POSIX_MADV_RANDOM); 200 #endif 201 return TRUE; 202 } 203 204 205 206 void uprv_unmapFile(UDataMemory * pData)207 uprv_unmapFile(UDataMemory *pData) { 208 if(pData!=NULL && pData->map!=NULL) { 209 size_t dataLen = (char *)pData->map - (char *)pData->mapAddr; 210 if(munmap(pData->mapAddr, dataLen)==-1) { 211 } 212 pData->pHeader=NULL; 213 pData->map=0; 214 pData->mapAddr=NULL; 215 } 216 } 217 218 219 220 #elif MAP_IMPLEMENTATION==MAP_STDIO 221 /* copy of the filestrm.c/T_FileStream_size() implementation */ 222 static int32_t umap_fsize(FILE * f)223 umap_fsize(FILE *f) { 224 int32_t savedPos = ftell(f); 225 int32_t size = 0; 226 227 /*Changes by Bertrand A. D. doesn't affect the current position 228 goes to the end of the file before ftell*/ 229 fseek(f, 0, SEEK_END); 230 size = (int32_t)ftell(f); 231 fseek(f, savedPos, SEEK_SET); 232 return size; 233 } 234 235 UBool uprv_mapFile(UDataMemory * pData,const char * path)236 uprv_mapFile(UDataMemory *pData, const char *path) { 237 FILE *file; 238 int32_t fileLength; 239 void *p; 240 241 UDataMemory_init(pData); /* Clear the output struct. */ 242 /* open the input file */ 243 file=fopen(path, "rb"); 244 if(file==NULL) { 245 return FALSE; 246 } 247 248 /* get the file length */ 249 fileLength=umap_fsize(file); 250 if(ferror(file) || fileLength<=20) { 251 fclose(file); 252 return FALSE; 253 } 254 255 /* allocate the memory to hold the file data */ 256 p=uprv_malloc(fileLength); 257 if(p==NULL) { 258 fclose(file); 259 return FALSE; 260 } 261 262 /* read the file */ 263 if(fileLength!=fread(p, 1, fileLength, file)) { 264 uprv_free(p); 265 fclose(file); 266 return FALSE; 267 } 268 269 fclose(file); 270 pData->map=p; 271 pData->pHeader=(const DataHeader *)p; 272 pData->mapAddr=p; 273 return TRUE; 274 } 275 276 void uprv_unmapFile(UDataMemory * pData)277 uprv_unmapFile(UDataMemory *pData) { 278 if(pData!=NULL && pData->map!=NULL) { 279 uprv_free(pData->map); 280 pData->map = NULL; 281 pData->mapAddr = NULL; 282 pData->pHeader = NULL; 283 } 284 } 285 286 287 #elif MAP_IMPLEMENTATION==MAP_390DLL 288 /* 390 specific Library Loading. 289 * This is the only platform left that dynamically loads an ICU Data Library. 290 * All other platforms use .data files when dynamic loading is required, but 291 * this turn out to be awkward to support in 390 batch mode. 292 * 293 * The idea here is to hide the fact that 390 is using dll loading from the 294 * rest of ICU, and make it look like there is file loading happening. 295 * 296 */ 297 strcpy_returnEnd(char * dest,const char * src)298 static char *strcpy_returnEnd(char *dest, const char *src) 299 { 300 while((*dest=*src)!=0) { 301 ++dest; 302 ++src; 303 } 304 return dest; 305 } 306 307 /*------------------------------------------------------------------------------ 308 * 309 * computeDirPath given a user-supplied path of an item to be opened, 310 * compute and return 311 * - the full directory path to be used 312 * when opening the file. 313 * - Pointer to null at end of above returned path 314 * 315 * Parameters: 316 * path: input path. Buffer is not altered. 317 * pathBuffer: Output buffer. Any contents are overwritten. 318 * 319 * Returns: 320 * Pointer to null termination in returned pathBuffer. 321 * 322 * TODO: This works the way ICU historically has, but the 323 * whole data fallback search path is so complicated that 324 * proabably almost no one will ever really understand it, 325 * the potential for confusion is large. (It's not just 326 * this one function, but the whole scheme.) 327 * 328 *------------------------------------------------------------------------------*/ uprv_computeDirPath(const char * path,char * pathBuffer)329 static char *uprv_computeDirPath(const char *path, char *pathBuffer) 330 { 331 char *finalSlash; /* Ptr to last dir separator in input path, or null if none. */ 332 int32_t pathLen; /* Length of the returned directory path */ 333 334 finalSlash = 0; 335 if (path != 0) { 336 finalSlash = uprv_strrchr(path, U_FILE_SEP_CHAR); 337 } 338 339 *pathBuffer = 0; 340 if (finalSlash == 0) { 341 /* No user-supplied path. 342 * Copy the ICU_DATA path to the path buffer and return that*/ 343 const char *icuDataDir; 344 icuDataDir=u_getDataDirectory(); 345 if(icuDataDir!=NULL && *icuDataDir!=0) { 346 return strcpy_returnEnd(pathBuffer, icuDataDir); 347 } else { 348 /* there is no icuDataDir either. Just return the empty pathBuffer. */ 349 return pathBuffer; 350 } 351 } 352 353 /* User supplied path did contain a directory portion. 354 * Copy it to the output path buffer */ 355 pathLen = (int32_t)(finalSlash - path + 1); 356 uprv_memcpy(pathBuffer, path, pathLen); 357 *(pathBuffer+pathLen) = 0; 358 return pathBuffer+pathLen; 359 } 360 361 362 # define DATA_TYPE "dat" 363 uprv_mapFile(UDataMemory * pData,const char * path)364 UBool uprv_mapFile(UDataMemory *pData, const char *path) { 365 const char *inBasename; 366 char *basename; 367 char pathBuffer[1024]; 368 const DataHeader *pHeader; 369 dllhandle *handle; 370 void *val=0; 371 372 inBasename=uprv_strrchr(path, U_FILE_SEP_CHAR); 373 if(inBasename==NULL) { 374 inBasename = path; 375 } else { 376 inBasename++; 377 } 378 basename=uprv_computeDirPath(path, pathBuffer); 379 if(uprv_strcmp(inBasename, U_ICUDATA_NAME".dat") != 0) { 380 /* must mmap file... for build */ 381 int fd; 382 int length; 383 struct stat mystat; 384 void *data; 385 UDataMemory_init(pData); /* Clear the output struct. */ 386 387 /* determine the length of the file */ 388 if(stat(path, &mystat)!=0 || mystat.st_size<=0) { 389 return FALSE; 390 } 391 length=mystat.st_size; 392 393 /* open the file */ 394 fd=open(path, O_RDONLY); 395 if(fd==-1) { 396 return FALSE; 397 } 398 399 /* get a view of the mapping */ 400 data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0); 401 close(fd); /* no longer needed */ 402 if(data==MAP_FAILED) { 403 return FALSE; 404 } 405 pData->map = (char *)data + length; 406 pData->pHeader=(const DataHeader *)data; 407 pData->mapAddr = data; 408 return TRUE; 409 } 410 411 # ifdef OS390BATCH 412 /* ### hack: we still need to get u_getDataDirectory() fixed 413 for OS/390 (batch mode - always return "//"? ) 414 and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!) 415 This is probably due to the strange file system on OS/390. It's more like 416 a database with short entry names than a typical file system. */ 417 /* U_ICUDATA_NAME should always have the correct name */ 418 /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */ 419 /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */ 420 /* PROJECT!!!!! */ 421 uprv_strcpy(pathBuffer, "IXMI" U_ICU_VERSION_SHORT "DA"); 422 # else 423 /* set up the library name */ 424 uprv_strcpy(basename, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX); 425 # endif 426 427 # ifdef UDATA_DEBUG 428 fprintf(stderr, "dllload: %s ", pathBuffer); 429 # endif 430 431 handle=dllload(pathBuffer); 432 433 # ifdef UDATA_DEBUG 434 fprintf(stderr, " -> %08X\n", handle ); 435 # endif 436 437 if(handle != NULL) { 438 /* we have a data DLL - what kind of lookup do we need here? */ 439 /* try to find the Table of Contents */ 440 UDataMemory_init(pData); /* Clear the output struct. */ 441 val=dllqueryvar((dllhandle*)handle, U_ICUDATA_ENTRY_NAME); 442 if(val == 0) { 443 /* failed... so keep looking */ 444 return FALSE; 445 } 446 # ifdef UDATA_DEBUG 447 fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", handle, U_ICUDATA_ENTRY_NAME, val); 448 # endif 449 450 pData->pHeader=(const DataHeader *)val; 451 return TRUE; 452 } else { 453 return FALSE; /* no handle */ 454 } 455 } 456 457 458 uprv_unmapFile(UDataMemory * pData)459 void uprv_unmapFile(UDataMemory *pData) { 460 if(pData!=NULL && pData->map!=NULL) { 461 uprv_free(pData->map); 462 pData->map = NULL; 463 pData->mapAddr = NULL; 464 pData->pHeader = NULL; 465 } 466 } 467 468 #else 469 # error MAP_IMPLEMENTATION is set incorrectly 470 #endif 471