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