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