1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/common/umapfile.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,464 @@ 1.4 +/* 1.5 +****************************************************************************** 1.6 +* 1.7 +* Copyright (C) 1999-2013, International Business Machines 1.8 +* Corporation and others. All Rights Reserved. 1.9 +* 1.10 +******************************************************************************/ 1.11 + 1.12 + 1.13 +/*---------------------------------------------------------------------------- 1.14 + * 1.15 + * Memory mapped file wrappers for use by the ICU Data Implementation 1.16 + * All of the platform-specific implementation for mapping data files 1.17 + * is here. The rest of the ICU Data implementation uses only the 1.18 + * wrapper functions. 1.19 + * 1.20 + *----------------------------------------------------------------------------*/ 1.21 +/* Defines _XOPEN_SOURCE for access to POSIX functions. 1.22 + * Must be before any other #includes. */ 1.23 +#include "uposixdefs.h" 1.24 + 1.25 +#include "unicode/putil.h" 1.26 +#include "udatamem.h" 1.27 +#include "umapfile.h" 1.28 + 1.29 +/* memory-mapping base definitions ------------------------------------------ */ 1.30 + 1.31 +#if MAP_IMPLEMENTATION==MAP_WIN32 1.32 +# define WIN32_LEAN_AND_MEAN 1.33 +# define VC_EXTRALEAN 1.34 +# define NOUSER 1.35 +# define NOSERVICE 1.36 +# define NOIME 1.37 +# define NOMCX 1.38 +# include <windows.h> 1.39 +# include "cmemory.h" 1.40 + 1.41 + typedef HANDLE MemoryMap; 1.42 + 1.43 +# define IS_MAP(map) ((map)!=NULL) 1.44 +#elif MAP_IMPLEMENTATION==MAP_POSIX || MAP_IMPLEMENTATION==MAP_390DLL 1.45 + typedef size_t MemoryMap; 1.46 + 1.47 +# define IS_MAP(map) ((map)!=0) 1.48 + 1.49 +# include <unistd.h> 1.50 +# include <sys/mman.h> 1.51 +# include <sys/stat.h> 1.52 +# include <fcntl.h> 1.53 + 1.54 +# ifndef MAP_FAILED 1.55 +# define MAP_FAILED ((void*)-1) 1.56 +# endif 1.57 + 1.58 +# if MAP_IMPLEMENTATION==MAP_390DLL 1.59 + /* No memory mapping for 390 batch mode. Fake it using dll loading. */ 1.60 +# include <dll.h> 1.61 +# include "cstring.h" 1.62 +# include "cmemory.h" 1.63 +# include "unicode/udata.h" 1.64 +# define LIB_PREFIX "lib" 1.65 +# define LIB_SUFFIX ".dll" 1.66 + /* This is inconvienient until we figure out what to do with U_ICUDATA_NAME in utypes.h */ 1.67 +# define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_NAME_STRING "_dat" 1.68 +# endif 1.69 +#elif MAP_IMPLEMENTATION==MAP_STDIO 1.70 +# include <stdio.h> 1.71 +# include "cmemory.h" 1.72 + 1.73 + typedef void *MemoryMap; 1.74 + 1.75 +# define IS_MAP(map) ((map)!=NULL) 1.76 +#endif 1.77 + 1.78 +/*----------------------------------------------------------------------------* 1.79 + * * 1.80 + * Memory Mapped File support. Platform dependent implementation of * 1.81 + * functions used by the rest of the implementation.* 1.82 + * * 1.83 + *----------------------------------------------------------------------------*/ 1.84 +#if MAP_IMPLEMENTATION==MAP_NONE 1.85 + U_CFUNC UBool 1.86 + uprv_mapFile(UDataMemory *pData, const char *path) { 1.87 + UDataMemory_init(pData); /* Clear the output struct. */ 1.88 + return FALSE; /* no file access */ 1.89 + } 1.90 + 1.91 + U_CFUNC void uprv_unmapFile(UDataMemory *pData) { 1.92 + /* nothing to do */ 1.93 + } 1.94 +#elif MAP_IMPLEMENTATION==MAP_WIN32 1.95 + U_CFUNC UBool 1.96 + uprv_mapFile( 1.97 + UDataMemory *pData, /* Fill in with info on the result doing the mapping. */ 1.98 + /* Output only; any original contents are cleared. */ 1.99 + const char *path /* File path to be opened/mapped */ 1.100 + ) 1.101 + { 1.102 + HANDLE map; 1.103 + HANDLE file; 1.104 + SECURITY_ATTRIBUTES mappingAttributes; 1.105 + SECURITY_ATTRIBUTES *mappingAttributesPtr = NULL; 1.106 + SECURITY_DESCRIPTOR securityDesc; 1.107 + 1.108 + UDataMemory_init(pData); /* Clear the output struct. */ 1.109 + 1.110 + /* open the input file */ 1.111 + file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, 1.112 + OPEN_EXISTING, 1.113 + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL); 1.114 + if(file==INVALID_HANDLE_VALUE) { 1.115 + return FALSE; 1.116 + } 1.117 + 1.118 + /* Declare and initialize a security descriptor. 1.119 + This is required for multiuser systems on Windows 2000 SP4 and beyond */ 1.120 + if (InitializeSecurityDescriptor(&securityDesc, SECURITY_DESCRIPTOR_REVISION)) { 1.121 + /* give the security descriptor a Null Dacl done using the "TRUE, (PACL)NULL" here */ 1.122 + if (SetSecurityDescriptorDacl(&securityDesc, TRUE, (PACL)NULL, FALSE)) { 1.123 + /* Make the security attributes point to the security descriptor */ 1.124 + uprv_memset(&mappingAttributes, 0, sizeof(mappingAttributes)); 1.125 + mappingAttributes.nLength = sizeof(mappingAttributes); 1.126 + mappingAttributes.lpSecurityDescriptor = &securityDesc; 1.127 + mappingAttributes.bInheritHandle = FALSE; /* object uninheritable */ 1.128 + mappingAttributesPtr = &mappingAttributes; 1.129 + } 1.130 + } 1.131 + /* else creating security descriptors can fail when we are on Windows 98, 1.132 + and mappingAttributesPtr == NULL for that case. */ 1.133 + 1.134 + /* create an unnamed Windows file-mapping object for the specified file */ 1.135 + map=CreateFileMapping(file, mappingAttributesPtr, PAGE_READONLY, 0, 0, NULL); 1.136 + CloseHandle(file); 1.137 + if(map==NULL) { 1.138 + return FALSE; 1.139 + } 1.140 + 1.141 + /* map a view of the file into our address space */ 1.142 + pData->pHeader=(const DataHeader *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0); 1.143 + if(pData->pHeader==NULL) { 1.144 + CloseHandle(map); 1.145 + return FALSE; 1.146 + } 1.147 + pData->map=map; 1.148 + return TRUE; 1.149 + } 1.150 + 1.151 + U_CFUNC void 1.152 + uprv_unmapFile(UDataMemory *pData) { 1.153 + if(pData!=NULL && pData->map!=NULL) { 1.154 + UnmapViewOfFile(pData->pHeader); 1.155 + CloseHandle(pData->map); 1.156 + pData->pHeader=NULL; 1.157 + pData->map=NULL; 1.158 + } 1.159 + } 1.160 + 1.161 + 1.162 + 1.163 +#elif MAP_IMPLEMENTATION==MAP_POSIX 1.164 + U_CFUNC UBool 1.165 + uprv_mapFile(UDataMemory *pData, const char *path) { 1.166 + int fd; 1.167 + int length; 1.168 + struct stat mystat; 1.169 + void *data; 1.170 + 1.171 + UDataMemory_init(pData); /* Clear the output struct. */ 1.172 + 1.173 + /* determine the length of the file */ 1.174 + if(stat(path, &mystat)!=0 || mystat.st_size<=0) { 1.175 + return FALSE; 1.176 + } 1.177 + length=mystat.st_size; 1.178 + 1.179 + /* open the file */ 1.180 + fd=open(path, O_RDONLY); 1.181 + if(fd==-1) { 1.182 + return FALSE; 1.183 + } 1.184 + 1.185 + /* get a view of the mapping */ 1.186 +#if U_PLATFORM != U_PF_HPUX 1.187 + data=mmap(0, length, PROT_READ, MAP_SHARED, fd, 0); 1.188 +#else 1.189 + data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0); 1.190 +#endif 1.191 + close(fd); /* no longer needed */ 1.192 + if(data==MAP_FAILED) { 1.193 + return FALSE; 1.194 + } 1.195 + 1.196 + pData->map = (char *)data + length; 1.197 + pData->pHeader=(const DataHeader *)data; 1.198 + pData->mapAddr = data; 1.199 +#if U_PLATFORM == U_PF_IPHONE 1.200 + posix_madvise(data, length, POSIX_MADV_RANDOM); 1.201 +#endif 1.202 + return TRUE; 1.203 + } 1.204 + 1.205 + U_CFUNC void 1.206 + uprv_unmapFile(UDataMemory *pData) { 1.207 + if(pData!=NULL && pData->map!=NULL) { 1.208 + size_t dataLen = (char *)pData->map - (char *)pData->mapAddr; 1.209 + if(munmap(pData->mapAddr, dataLen)==-1) { 1.210 + } 1.211 + pData->pHeader=NULL; 1.212 + pData->map=0; 1.213 + pData->mapAddr=NULL; 1.214 + } 1.215 + } 1.216 + 1.217 + 1.218 + 1.219 +#elif MAP_IMPLEMENTATION==MAP_STDIO 1.220 + /* copy of the filestrm.c/T_FileStream_size() implementation */ 1.221 + static int32_t 1.222 + umap_fsize(FILE *f) { 1.223 + int32_t savedPos = ftell(f); 1.224 + int32_t size = 0; 1.225 + 1.226 + /*Changes by Bertrand A. D. doesn't affect the current position 1.227 + goes to the end of the file before ftell*/ 1.228 + fseek(f, 0, SEEK_END); 1.229 + size = (int32_t)ftell(f); 1.230 + fseek(f, savedPos, SEEK_SET); 1.231 + return size; 1.232 + } 1.233 + 1.234 + U_CFUNC UBool 1.235 + uprv_mapFile(UDataMemory *pData, const char *path) { 1.236 + FILE *file; 1.237 + int32_t fileLength; 1.238 + void *p; 1.239 + 1.240 + UDataMemory_init(pData); /* Clear the output struct. */ 1.241 + /* open the input file */ 1.242 + file=fopen(path, "rb"); 1.243 + if(file==NULL) { 1.244 + return FALSE; 1.245 + } 1.246 + 1.247 + /* get the file length */ 1.248 + fileLength=umap_fsize(file); 1.249 + if(ferror(file) || fileLength<=20) { 1.250 + fclose(file); 1.251 + return FALSE; 1.252 + } 1.253 + 1.254 + /* allocate the memory to hold the file data */ 1.255 + p=uprv_malloc(fileLength); 1.256 + if(p==NULL) { 1.257 + fclose(file); 1.258 + return FALSE; 1.259 + } 1.260 + 1.261 + /* read the file */ 1.262 + if(fileLength!=fread(p, 1, fileLength, file)) { 1.263 + uprv_free(p); 1.264 + fclose(file); 1.265 + return FALSE; 1.266 + } 1.267 + 1.268 + fclose(file); 1.269 + pData->map=p; 1.270 + pData->pHeader=(const DataHeader *)p; 1.271 + pData->mapAddr=p; 1.272 + return TRUE; 1.273 + } 1.274 + 1.275 + U_CFUNC void 1.276 + uprv_unmapFile(UDataMemory *pData) { 1.277 + if(pData!=NULL && pData->map!=NULL) { 1.278 + uprv_free(pData->map); 1.279 + pData->map = NULL; 1.280 + pData->mapAddr = NULL; 1.281 + pData->pHeader = NULL; 1.282 + } 1.283 + } 1.284 + 1.285 + 1.286 +#elif MAP_IMPLEMENTATION==MAP_390DLL 1.287 + /* 390 specific Library Loading. 1.288 + * This is the only platform left that dynamically loads an ICU Data Library. 1.289 + * All other platforms use .data files when dynamic loading is required, but 1.290 + * this turn out to be awkward to support in 390 batch mode. 1.291 + * 1.292 + * The idea here is to hide the fact that 390 is using dll loading from the 1.293 + * rest of ICU, and make it look like there is file loading happening. 1.294 + * 1.295 + */ 1.296 + 1.297 + static char *strcpy_returnEnd(char *dest, const char *src) 1.298 + { 1.299 + while((*dest=*src)!=0) { 1.300 + ++dest; 1.301 + ++src; 1.302 + } 1.303 + return dest; 1.304 + } 1.305 + 1.306 + /*------------------------------------------------------------------------------ 1.307 + * 1.308 + * computeDirPath given a user-supplied path of an item to be opened, 1.309 + * compute and return 1.310 + * - the full directory path to be used 1.311 + * when opening the file. 1.312 + * - Pointer to null at end of above returned path 1.313 + * 1.314 + * Parameters: 1.315 + * path: input path. Buffer is not altered. 1.316 + * pathBuffer: Output buffer. Any contents are overwritten. 1.317 + * 1.318 + * Returns: 1.319 + * Pointer to null termination in returned pathBuffer. 1.320 + * 1.321 + * TODO: This works the way ICU historically has, but the 1.322 + * whole data fallback search path is so complicated that 1.323 + * proabably almost no one will ever really understand it, 1.324 + * the potential for confusion is large. (It's not just 1.325 + * this one function, but the whole scheme.) 1.326 + * 1.327 + *------------------------------------------------------------------------------*/ 1.328 + static char *uprv_computeDirPath(const char *path, char *pathBuffer) 1.329 + { 1.330 + char *finalSlash; /* Ptr to last dir separator in input path, or null if none. */ 1.331 + int32_t pathLen; /* Length of the returned directory path */ 1.332 + 1.333 + finalSlash = 0; 1.334 + if (path != 0) { 1.335 + finalSlash = uprv_strrchr(path, U_FILE_SEP_CHAR); 1.336 + } 1.337 + 1.338 + *pathBuffer = 0; 1.339 + if (finalSlash == 0) { 1.340 + /* No user-supplied path. 1.341 + * Copy the ICU_DATA path to the path buffer and return that*/ 1.342 + const char *icuDataDir; 1.343 + icuDataDir=u_getDataDirectory(); 1.344 + if(icuDataDir!=NULL && *icuDataDir!=0) { 1.345 + return strcpy_returnEnd(pathBuffer, icuDataDir); 1.346 + } else { 1.347 + /* there is no icuDataDir either. Just return the empty pathBuffer. */ 1.348 + return pathBuffer; 1.349 + } 1.350 + } 1.351 + 1.352 + /* User supplied path did contain a directory portion. 1.353 + * Copy it to the output path buffer */ 1.354 + pathLen = (int32_t)(finalSlash - path + 1); 1.355 + uprv_memcpy(pathBuffer, path, pathLen); 1.356 + *(pathBuffer+pathLen) = 0; 1.357 + return pathBuffer+pathLen; 1.358 + } 1.359 + 1.360 + 1.361 +# define DATA_TYPE "dat" 1.362 + 1.363 + U_CFUNC UBool uprv_mapFile(UDataMemory *pData, const char *path) { 1.364 + const char *inBasename; 1.365 + char *basename; 1.366 + char pathBuffer[1024]; 1.367 + const DataHeader *pHeader; 1.368 + dllhandle *handle; 1.369 + void *val=0; 1.370 + 1.371 + inBasename=uprv_strrchr(path, U_FILE_SEP_CHAR); 1.372 + if(inBasename==NULL) { 1.373 + inBasename = path; 1.374 + } else { 1.375 + inBasename++; 1.376 + } 1.377 + basename=uprv_computeDirPath(path, pathBuffer); 1.378 + if(uprv_strcmp(inBasename, U_ICUDATA_NAME".dat") != 0) { 1.379 + /* must mmap file... for build */ 1.380 + int fd; 1.381 + int length; 1.382 + struct stat mystat; 1.383 + void *data; 1.384 + UDataMemory_init(pData); /* Clear the output struct. */ 1.385 + 1.386 + /* determine the length of the file */ 1.387 + if(stat(path, &mystat)!=0 || mystat.st_size<=0) { 1.388 + return FALSE; 1.389 + } 1.390 + length=mystat.st_size; 1.391 + 1.392 + /* open the file */ 1.393 + fd=open(path, O_RDONLY); 1.394 + if(fd==-1) { 1.395 + return FALSE; 1.396 + } 1.397 + 1.398 + /* get a view of the mapping */ 1.399 + data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0); 1.400 + close(fd); /* no longer needed */ 1.401 + if(data==MAP_FAILED) { 1.402 + return FALSE; 1.403 + } 1.404 + pData->map = (char *)data + length; 1.405 + pData->pHeader=(const DataHeader *)data; 1.406 + pData->mapAddr = data; 1.407 + return TRUE; 1.408 + } 1.409 + 1.410 +# ifdef OS390BATCH 1.411 + /* ### hack: we still need to get u_getDataDirectory() fixed 1.412 + for OS/390 (batch mode - always return "//"? ) 1.413 + and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!) 1.414 + This is probably due to the strange file system on OS/390. It's more like 1.415 + a database with short entry names than a typical file system. */ 1.416 + /* U_ICUDATA_NAME should always have the correct name */ 1.417 + /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */ 1.418 + /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */ 1.419 + /* PROJECT!!!!! */ 1.420 + uprv_strcpy(pathBuffer, "IXMI" U_ICU_VERSION_SHORT "DA"); 1.421 +# else 1.422 + /* set up the library name */ 1.423 + uprv_strcpy(basename, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX); 1.424 +# endif 1.425 + 1.426 +# ifdef UDATA_DEBUG 1.427 + fprintf(stderr, "dllload: %s ", pathBuffer); 1.428 +# endif 1.429 + 1.430 + handle=dllload(pathBuffer); 1.431 + 1.432 +# ifdef UDATA_DEBUG 1.433 + fprintf(stderr, " -> %08X\n", handle ); 1.434 +# endif 1.435 + 1.436 + if(handle != NULL) { 1.437 + /* we have a data DLL - what kind of lookup do we need here? */ 1.438 + /* try to find the Table of Contents */ 1.439 + UDataMemory_init(pData); /* Clear the output struct. */ 1.440 + val=dllqueryvar((dllhandle*)handle, U_ICUDATA_ENTRY_NAME); 1.441 + if(val == 0) { 1.442 + /* failed... so keep looking */ 1.443 + return FALSE; 1.444 + } 1.445 +# ifdef UDATA_DEBUG 1.446 + fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", handle, U_ICUDATA_ENTRY_NAME, val); 1.447 +# endif 1.448 + 1.449 + pData->pHeader=(const DataHeader *)val; 1.450 + return TRUE; 1.451 + } else { 1.452 + return FALSE; /* no handle */ 1.453 + } 1.454 + } 1.455 + 1.456 + U_CFUNC void uprv_unmapFile(UDataMemory *pData) { 1.457 + if(pData!=NULL && pData->map!=NULL) { 1.458 + uprv_free(pData->map); 1.459 + pData->map = NULL; 1.460 + pData->mapAddr = NULL; 1.461 + pData->pHeader = NULL; 1.462 + } 1.463 + } 1.464 + 1.465 +#else 1.466 +# error MAP_IMPLEMENTATION is set incorrectly 1.467 +#endif