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