intl/icu/source/common/umapfile.c

changeset 0
6474c204b198
     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

mercurial