Coverage Report

Created: 2018-09-25 14:53

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