LCOV - code coverage report
Current view: top level - intl/icu/source/common - umapfile.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 14 24 58.3 %
Date: 2017-07-14 16:53:18 Functions: 1 2 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : ******************************************************************************
       5             : *
       6             : *   Copyright (C) 1999-2013, International Business Machines
       7             : *   Corporation and others.  All Rights Reserved.
       8             : *
       9             : ******************************************************************************/
      10             : 
      11             : 
      12             : /*----------------------------------------------------------------------------
      13             :  *
      14             :  *       Memory mapped file wrappers for use by the ICU Data Implementation
      15             :  *       All of the platform-specific implementation for mapping data files
      16             :  *         is here.  The rest of the ICU Data implementation uses only the
      17             :  *         wrapper functions.
      18             :  *
      19             :  *----------------------------------------------------------------------------*/
      20             : /* Defines _XOPEN_SOURCE for access to POSIX functions.
      21             :  * Must be before any other #includes. */
      22             : #include "uposixdefs.h"
      23             : 
      24             : #include "unicode/putil.h"
      25             : #include "udatamem.h"
      26             : #include "umapfile.h"
      27             : 
      28             : /* memory-mapping base definitions ------------------------------------------ */
      29             : 
      30             : #if MAP_IMPLEMENTATION==MAP_WIN32
      31             : #ifndef WIN32_LEAN_AND_MEAN
      32             : #   define WIN32_LEAN_AND_MEAN
      33             : #endif
      34             : #   define VC_EXTRALEAN
      35             : #   define NOUSER
      36             : #   define NOSERVICE
      37             : #   define NOIME
      38             : #   define NOMCX
      39             : #   include <windows.h>
      40             : #   include "cmemory.h"
      41             : 
      42             :     typedef HANDLE MemoryMap;
      43             : 
      44             : #   define IS_MAP(map) ((map)!=NULL)
      45             : #elif MAP_IMPLEMENTATION==MAP_POSIX || MAP_IMPLEMENTATION==MAP_390DLL
      46             :     typedef size_t MemoryMap;
      47             : 
      48             : #   define IS_MAP(map) ((map)!=0)
      49             : 
      50             : #   include <unistd.h>
      51             : #   include <sys/mman.h>
      52             : #   include <sys/stat.h>
      53             : #   include <fcntl.h>
      54             : 
      55             : #   ifndef MAP_FAILED
      56             : #       define MAP_FAILED ((void*)-1)
      57             : #   endif
      58             : 
      59             : #   if MAP_IMPLEMENTATION==MAP_390DLL
      60             :         /*   No memory mapping for 390 batch mode.  Fake it using dll loading.  */
      61             : #       include <dll.h>
      62             : #       include "cstring.h"
      63             : #       include "cmemory.h"
      64             : #       include "unicode/udata.h"
      65             : #       define LIB_PREFIX "lib"
      66             : #       define LIB_SUFFIX ".dll"
      67             :         /* This is inconvienient until we figure out what to do with U_ICUDATA_NAME in utypes.h */
      68             : #       define U_ICUDATA_ENTRY_NAME "icudt" U_ICU_VERSION_SHORT U_LIB_SUFFIX_C_NAME_STRING "_dat"
      69             : #   endif
      70             : #elif MAP_IMPLEMENTATION==MAP_STDIO
      71             : #   include <stdio.h>
      72             : #   include "cmemory.h"
      73             : 
      74             :     typedef void *MemoryMap;
      75             : 
      76             : #   define IS_MAP(map) ((map)!=NULL)
      77             : #endif
      78             : 
      79             : /*----------------------------------------------------------------------------*
      80             :  *                                                                            *
      81             :  *   Memory Mapped File support.  Platform dependent implementation of        *
      82             :  *                           functions used by the rest of the implementation.*
      83             :  *                                                                            *
      84             :  *----------------------------------------------------------------------------*/
      85             : #if MAP_IMPLEMENTATION==MAP_NONE
      86             :     U_CFUNC UBool
      87             :     uprv_mapFile(UDataMemory *pData, const char *path) {
      88             :         UDataMemory_init(pData); /* Clear the output struct. */
      89             :         return FALSE;            /* no file access */
      90             :     }
      91             : 
      92             :     U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
      93             :         /* nothing to do */
      94             :     }
      95             : #elif MAP_IMPLEMENTATION==MAP_WIN32
      96             :     U_CFUNC UBool
      97             :     uprv_mapFile(
      98             :          UDataMemory *pData,    /* Fill in with info on the result doing the mapping. */
      99             :                                 /*   Output only; any original contents are cleared.  */
     100             :          const char *path       /* File path to be opened/mapped                      */
     101             :          )
     102             :     {
     103             :         HANDLE map;
     104             :         HANDLE file;
     105             :         SECURITY_ATTRIBUTES mappingAttributes;
     106             :         SECURITY_ATTRIBUTES *mappingAttributesPtr = NULL;
     107             :         SECURITY_DESCRIPTOR securityDesc;
     108             : 
     109             :         UDataMemory_init(pData); /* Clear the output struct.        */
     110             : 
     111             :         /* open the input file */
     112             : #if U_PLATFORM_HAS_WINUWP_API == 0
     113             :         file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
     114             :             OPEN_EXISTING,
     115             :             FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
     116             : #else
     117             :         // First we need to go from char to UTF-16
     118             :         // u_UCharsToChars could work but it requires length.
     119             :         WCHAR utf16Path[MAX_PATH];
     120             :         int32_t i;
     121             :         for (i = 0; i < UPRV_LENGTHOF(utf16Path); i++)
     122             :         {
     123             :             utf16Path[i] = path[i];
     124             :             if (path[i] == '\0')
     125             :             {
     126             :                 break;
     127             :             }
     128             :         }
     129             :         if (i >= UPRV_LENGTHOF(utf16Path))
     130             :         {
     131             :             // Ran out of room, unlikely but be safe
     132             :             utf16Path[UPRV_LENGTHOF(utf16Path) - 1] = '\0';
     133             :         }
     134             : 
     135             :         // TODO: Is it worth setting extended parameters to specify random access?
     136             :         file = CreateFile2(utf16Path, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, NULL);
     137             : #endif
     138             :         if(file==INVALID_HANDLE_VALUE) {
     139             :             return FALSE;
     140             :         }
     141             : 
     142             :         /* Declare and initialize a security descriptor.
     143             :            This is required for multiuser systems on Windows 2000 SP4 and beyond */
     144             :         // TODO: UWP does not have this function and I do not think it is required?
     145             : #if U_PLATFORM_HAS_WINUWP_API == 0
     146             :         if (InitializeSecurityDescriptor(&securityDesc, SECURITY_DESCRIPTOR_REVISION)) {
     147             :             /* give the security descriptor a Null Dacl done using the  "TRUE, (PACL)NULL" here */
     148             :             if (SetSecurityDescriptorDacl(&securityDesc, TRUE, (PACL)NULL, FALSE)) {
     149             :                 /* Make the security attributes point to the security descriptor */
     150             :                 uprv_memset(&mappingAttributes, 0, sizeof(mappingAttributes));
     151             :                 mappingAttributes.nLength = sizeof(mappingAttributes);
     152             :                 mappingAttributes.lpSecurityDescriptor = &securityDesc;
     153             :                 mappingAttributes.bInheritHandle = FALSE; /* object uninheritable */
     154             :                 mappingAttributesPtr = &mappingAttributes;
     155             :             }
     156             :         }
     157             :         /* else creating security descriptors can fail when we are on Windows 98,
     158             :            and mappingAttributesPtr == NULL for that case. */
     159             : 
     160             :         /* create an unnamed Windows file-mapping object for the specified file */
     161             :         map=CreateFileMapping(file, mappingAttributesPtr, PAGE_READONLY, 0, 0, NULL);
     162             : #else
     163             :         map = CreateFileMappingFromApp(file, NULL, PAGE_READONLY, 0, NULL);
     164             : #endif
     165             :         CloseHandle(file);
     166             :         if(map==NULL) {
     167             :             return FALSE;
     168             :         }
     169             : 
     170             :         /* map a view of the file into our address space */
     171             :         pData->pHeader=(const DataHeader *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
     172             :         if(pData->pHeader==NULL) {
     173             :             CloseHandle(map);
     174             :             return FALSE;
     175             :         }
     176             :         pData->map=map;
     177             :         return TRUE;
     178             :     }
     179             : 
     180             :     U_CFUNC void
     181             :     uprv_unmapFile(UDataMemory *pData) {
     182             :         if(pData!=NULL && pData->map!=NULL) {
     183             :             UnmapViewOfFile(pData->pHeader);
     184             :             CloseHandle(pData->map);
     185             :             pData->pHeader=NULL;
     186             :             pData->map=NULL;
     187             :         }
     188             :     }
     189             : 
     190             : 
     191             : 
     192             : #elif MAP_IMPLEMENTATION==MAP_POSIX
     193             :     U_CFUNC UBool
     194          10 :     uprv_mapFile(UDataMemory *pData, const char *path) {
     195             :         int fd;
     196             :         int length;
     197             :         struct stat mystat;
     198             :         void *data;
     199             : 
     200          10 :         UDataMemory_init(pData); /* Clear the output struct.        */
     201             : 
     202             :         /* determine the length of the file */
     203          10 :         if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
     204           7 :             return FALSE;
     205             :         }
     206           3 :         length=mystat.st_size;
     207             : 
     208             :         /* open the file */
     209           3 :         fd=open(path, O_RDONLY);
     210           3 :         if(fd==-1) {
     211           0 :             return FALSE;
     212             :         }
     213             : 
     214             :         /* get a view of the mapping */
     215             : #if U_PLATFORM != U_PF_HPUX
     216           3 :         data=mmap(0, length, PROT_READ, MAP_SHARED,  fd, 0);
     217             : #else
     218             :         data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
     219             : #endif
     220           3 :         close(fd); /* no longer needed */
     221           3 :         if(data==MAP_FAILED) {
     222           0 :             return FALSE;
     223             :         }
     224             : 
     225           3 :         pData->map = (char *)data + length;
     226           3 :         pData->pHeader=(const DataHeader *)data;
     227           3 :         pData->mapAddr = data;
     228             : #if U_PLATFORM == U_PF_IPHONE
     229             :         posix_madvise(data, length, POSIX_MADV_RANDOM);
     230             : #endif
     231           3 :         return TRUE;
     232             :     }
     233             : 
     234             :     U_CFUNC void
     235           0 :     uprv_unmapFile(UDataMemory *pData) {
     236           0 :         if(pData!=NULL && pData->map!=NULL) {
     237           0 :             size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
     238           0 :             if(munmap(pData->mapAddr, dataLen)==-1) {
     239             :             }
     240           0 :             pData->pHeader=NULL;
     241           0 :             pData->map=0;
     242           0 :             pData->mapAddr=NULL;
     243             :         }
     244           0 :     }
     245             : 
     246             : 
     247             : 
     248             : #elif MAP_IMPLEMENTATION==MAP_STDIO
     249             :     /* copy of the filestrm.c/T_FileStream_size() implementation */
     250             :     static int32_t
     251             :     umap_fsize(FILE *f) {
     252             :         int32_t savedPos = ftell(f);
     253             :         int32_t size = 0;
     254             : 
     255             :         /*Changes by Bertrand A. D. doesn't affect the current position
     256             :         goes to the end of the file before ftell*/
     257             :         fseek(f, 0, SEEK_END);
     258             :         size = (int32_t)ftell(f);
     259             :         fseek(f, savedPos, SEEK_SET);
     260             :         return size;
     261             :     }
     262             : 
     263             :     U_CFUNC UBool
     264             :     uprv_mapFile(UDataMemory *pData, const char *path) {
     265             :         FILE *file;
     266             :         int32_t fileLength;
     267             :         void *p;
     268             : 
     269             :         UDataMemory_init(pData); /* Clear the output struct.        */
     270             :         /* open the input file */
     271             :         file=fopen(path, "rb");
     272             :         if(file==NULL) {
     273             :             return FALSE;
     274             :         }
     275             : 
     276             :         /* get the file length */
     277             :         fileLength=umap_fsize(file);
     278             :         if(ferror(file) || fileLength<=20) {
     279             :             fclose(file);
     280             :             return FALSE;
     281             :         }
     282             : 
     283             :         /* allocate the memory to hold the file data */
     284             :         p=uprv_malloc(fileLength);
     285             :         if(p==NULL) {
     286             :             fclose(file);
     287             :             return FALSE;
     288             :         }
     289             : 
     290             :         /* read the file */
     291             :         if(fileLength!=fread(p, 1, fileLength, file)) {
     292             :             uprv_free(p);
     293             :             fclose(file);
     294             :             return FALSE;
     295             :         }
     296             : 
     297             :         fclose(file);
     298             :         pData->map=p;
     299             :         pData->pHeader=(const DataHeader *)p;
     300             :         pData->mapAddr=p;
     301             :         return TRUE;
     302             :     }
     303             : 
     304             :     U_CFUNC void
     305             :     uprv_unmapFile(UDataMemory *pData) {
     306             :         if(pData!=NULL && pData->map!=NULL) {
     307             :             uprv_free(pData->map);
     308             :             pData->map     = NULL;
     309             :             pData->mapAddr = NULL;
     310             :             pData->pHeader = NULL;
     311             :         }
     312             :     }
     313             : 
     314             : 
     315             : #elif MAP_IMPLEMENTATION==MAP_390DLL
     316             :     /*  390 specific Library Loading.
     317             :      *  This is the only platform left that dynamically loads an ICU Data Library.
     318             :      *  All other platforms use .data files when dynamic loading is required, but
     319             :      *  this turn out to be awkward to support in 390 batch mode.
     320             :      *
     321             :      *  The idea here is to hide the fact that 390 is using dll loading from the
     322             :      *   rest of ICU, and make it look like there is file loading happening.
     323             :      *
     324             :      */
     325             : 
     326             :     static char *strcpy_returnEnd(char *dest, const char *src)
     327             :     {
     328             :         while((*dest=*src)!=0) {
     329             :             ++dest;
     330             :             ++src;
     331             :         }
     332             :         return dest;
     333             :     }
     334             :     
     335             :     /*------------------------------------------------------------------------------
     336             :      *                                                                              
     337             :      *  computeDirPath   given a user-supplied path of an item to be opened,             
     338             :      *                         compute and return 
     339             :      *                            - the full directory path to be used 
     340             :      *                              when opening the file.
     341             :      *                            - Pointer to null at end of above returned path    
     342             :      *
     343             :      *                       Parameters:
     344             :      *                          path:        input path.  Buffer is not altered.
     345             :      *                          pathBuffer:  Output buffer.  Any contents are overwritten.
     346             :      *
     347             :      *                       Returns:
     348             :      *                          Pointer to null termination in returned pathBuffer.
     349             :      *
     350             :      *                    TODO:  This works the way ICU historically has, but the
     351             :      *                           whole data fallback search path is so complicated that
     352             :      *                           proabably almost no one will ever really understand it,
     353             :      *                           the potential for confusion is large.  (It's not just 
     354             :      *                           this one function, but the whole scheme.)
     355             :      *                            
     356             :      *------------------------------------------------------------------------------*/
     357             :     static char *uprv_computeDirPath(const char *path, char *pathBuffer)
     358             :     {
     359             :         char   *finalSlash;       /* Ptr to last dir separator in input path, or null if none. */
     360             :         int32_t pathLen;          /* Length of the returned directory path                     */
     361             :         
     362             :         finalSlash = 0;
     363             :         if (path != 0) {
     364             :             finalSlash = uprv_strrchr(path, U_FILE_SEP_CHAR);
     365             :         }
     366             :         
     367             :         *pathBuffer = 0;
     368             :         if (finalSlash == 0) {
     369             :         /* No user-supplied path.  
     370             :             * Copy the ICU_DATA path to the path buffer and return that*/
     371             :             const char *icuDataDir;
     372             :             icuDataDir=u_getDataDirectory();
     373             :             if(icuDataDir!=NULL && *icuDataDir!=0) {
     374             :                 return strcpy_returnEnd(pathBuffer, icuDataDir);
     375             :             } else {
     376             :                 /* there is no icuDataDir either.  Just return the empty pathBuffer. */
     377             :                 return pathBuffer;
     378             :             }
     379             :         } 
     380             :         
     381             :         /* User supplied path did contain a directory portion.
     382             :         * Copy it to the output path buffer */
     383             :         pathLen = (int32_t)(finalSlash - path + 1);
     384             :         uprv_memcpy(pathBuffer, path, pathLen);
     385             :         *(pathBuffer+pathLen) = 0;
     386             :         return pathBuffer+pathLen;
     387             :     }
     388             :     
     389             : 
     390             : #   define DATA_TYPE "dat"
     391             : 
     392             :     U_CFUNC UBool uprv_mapFile(UDataMemory *pData, const char *path) {
     393             :         const char *inBasename;
     394             :         char *basename;
     395             :         char pathBuffer[1024];
     396             :         const DataHeader *pHeader;
     397             :         dllhandle *handle;
     398             :         void *val=0;
     399             : 
     400             :         inBasename=uprv_strrchr(path, U_FILE_SEP_CHAR);
     401             :         if(inBasename==NULL) {
     402             :             inBasename = path;
     403             :         } else {
     404             :             inBasename++;
     405             :         }
     406             :         basename=uprv_computeDirPath(path, pathBuffer);
     407             :         if(uprv_strcmp(inBasename, U_ICUDATA_NAME".dat") != 0) {
     408             :             /* must mmap file... for build */
     409             :             int fd;
     410             :             int length;
     411             :             struct stat mystat;
     412             :             void *data;
     413             :             UDataMemory_init(pData); /* Clear the output struct. */
     414             : 
     415             :             /* determine the length of the file */
     416             :             if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
     417             :                 return FALSE;
     418             :             }
     419             :             length=mystat.st_size;
     420             : 
     421             :             /* open the file */
     422             :             fd=open(path, O_RDONLY);
     423             :             if(fd==-1) {
     424             :                 return FALSE;
     425             :             }
     426             : 
     427             :             /* get a view of the mapping */
     428             :             data=mmap(0, length, PROT_READ, MAP_PRIVATE, fd, 0);
     429             :             close(fd); /* no longer needed */
     430             :             if(data==MAP_FAILED) {
     431             :                 return FALSE;
     432             :             }
     433             :             pData->map = (char *)data + length;
     434             :             pData->pHeader=(const DataHeader *)data;
     435             :             pData->mapAddr = data;
     436             :             return TRUE;
     437             :         }
     438             : 
     439             : #       ifdef OS390BATCH
     440             :             /* ### hack: we still need to get u_getDataDirectory() fixed
     441             :             for OS/390 (batch mode - always return "//"? )
     442             :             and this here straightened out with LIB_PREFIX and LIB_SUFFIX (both empty?!)
     443             :             This is probably due to the strange file system on OS/390.  It's more like
     444             :             a database with short entry names than a typical file system. */
     445             :             /* U_ICUDATA_NAME should always have the correct name */
     446             :             /* BUT FOR BATCH MODE IT IS AN EXCEPTION BECAUSE */
     447             :             /* THE FIRST THREE LETTERS ARE PREASSIGNED TO THE */
     448             :             /* PROJECT!!!!! */
     449             :             uprv_strcpy(pathBuffer, "IXMI" U_ICU_VERSION_SHORT "DA");
     450             : #       else
     451             :             /* set up the library name */
     452             :             uprv_strcpy(basename, LIB_PREFIX U_LIBICUDATA_NAME U_ICU_VERSION_SHORT LIB_SUFFIX);
     453             : #       endif
     454             : 
     455             : #       ifdef UDATA_DEBUG
     456             :              fprintf(stderr, "dllload: %s ", pathBuffer);
     457             : #       endif
     458             : 
     459             :         handle=dllload(pathBuffer);
     460             : 
     461             : #       ifdef UDATA_DEBUG
     462             :                fprintf(stderr, " -> %08X\n", handle );
     463             : #       endif
     464             : 
     465             :         if(handle != NULL) {
     466             :                /* we have a data DLL - what kind of lookup do we need here? */
     467             :                /* try to find the Table of Contents */
     468             :                UDataMemory_init(pData); /* Clear the output struct.        */
     469             :                val=dllqueryvar((dllhandle*)handle, U_ICUDATA_ENTRY_NAME);
     470             :                if(val == 0) {
     471             :                     /* failed... so keep looking */
     472             :                     return FALSE;
     473             :                }
     474             : #              ifdef UDATA_DEBUG
     475             :                     fprintf(stderr, "dllqueryvar(%08X, %s) -> %08X\n", handle, U_ICUDATA_ENTRY_NAME, val);
     476             : #              endif
     477             : 
     478             :                pData->pHeader=(const DataHeader *)val;
     479             :                return TRUE;
     480             :          } else {
     481             :                return FALSE; /* no handle */
     482             :          }
     483             :     }
     484             : 
     485             :     U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
     486             :         if(pData!=NULL && pData->map!=NULL) {
     487             :             uprv_free(pData->map);
     488             :             pData->map     = NULL;
     489             :             pData->mapAddr = NULL;
     490             :             pData->pHeader = NULL;
     491             :         }   
     492             :     }
     493             : 
     494             : #else
     495             : #   error MAP_IMPLEMENTATION is set incorrectly
     496             : #endif

Generated by: LCOV version 1.13