OLD | NEW |
(Empty) | |
| 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_N
AME in utypes.h */ |
| 61 # define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_N
AME_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 map
ping. */ |
| 96 /* Output only; any original contents are clea
red. */ |
| 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_REVI
SION)) { |
| 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 uninheritabl
e */ |
| 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, N
ULL); |
| 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 Librar
y. |
| 287 * All other platforms use .data files when dynamic loading is required, bu
t |
| 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 pat
h |
| 311 * |
| 312 * Parameters: |
| 313 * path: input path. Buffer is not altered. |
| 314 * pathBuffer: Output buffer. Any contents are ov
erwritten. |
| 315 * |
| 316 * Returns: |
| 317 * Pointer to null termination in returned pathBuff
er. |
| 318 * |
| 319 * TODO: This works the way ICU historically has, but th
e |
| 320 * whole data fallback search path is so complicat
ed that |
| 321 * proabably almost no one will ever really unders
tand it, |
| 322 * the potential for confusion is large. (It's no
t 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 pathBuf
fer. */ |
| 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 mor
e 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_SHO
RT 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 |
OLD | NEW |