tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

umapfile.cpp (11445B)


      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 "unicode/ustring.h"
     26 #include "udatamem.h"
     27 #include "umapfile.h"
     28 
     29 /* memory-mapping base definitions ------------------------------------------ */
     30 
     31 #if MAP_IMPLEMENTATION==MAP_WIN32
     32 #ifndef WIN32_LEAN_AND_MEAN
     33 #   define WIN32_LEAN_AND_MEAN
     34 #endif
     35 #   define VC_EXTRALEAN
     36 #   define NOUSER
     37 #   define NOSERVICE
     38 #   define NOIME
     39 #   define NOMCX
     40 
     41 #   if U_PLATFORM_HAS_WINUWP_API == 1
     42        // Some previous versions of the Windows 10 SDK don't expose various APIs for UWP applications
     43        // to use, even though UWP apps are allowed to call and use them.  Temporarily change the
     44        // WINAPI family partition below to Desktop, so that function declarations are visible for UWP.
     45 #       include <winapifamily.h>
     46 #       if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM))
     47 #           pragma push_macro("WINAPI_PARTITION_DESKTOP")
     48 #           undef WINAPI_PARTITION_DESKTOP
     49 #           define WINAPI_PARTITION_DESKTOP 1
     50 #           define CHANGED_WINAPI_PARTITION_DESKTOP_VALUE
     51 #       endif
     52 #   endif
     53 
     54 #   include <windows.h>
     55 
     56 #   if U_PLATFORM_HAS_WINUWP_API == 1 && defined(CHANGED_WINAPI_PARTITION_DESKTOP_VALUE)
     57 #       pragma pop_macro("WINAPI_PARTITION_DESKTOP")
     58 #   endif
     59 
     60 #   include "cmemory.h"
     61 
     62 typedef HANDLE MemoryMap;
     63 
     64 #   define IS_MAP(map) ((map)!=nullptr)
     65 
     66 #elif MAP_IMPLEMENTATION==MAP_POSIX
     67    typedef size_t MemoryMap;
     68 
     69 #   define IS_MAP(map) ((map)!=0)
     70 
     71 #   include <unistd.h>
     72 #   include <sys/mman.h>
     73 #   include <sys/stat.h>
     74 #   include <fcntl.h>
     75 
     76 #   ifndef MAP_FAILED
     77 #       define MAP_FAILED ((void*)-1)
     78 #   endif
     79 #elif MAP_IMPLEMENTATION==MAP_STDIO
     80 #   include <stdio.h>
     81 #   include "cmemory.h"
     82 
     83    typedef void *MemoryMap;
     84 
     85 #   define IS_MAP(map) ((map)!=nullptr)
     86 #endif
     87 
     88 /*----------------------------------------------------------------------------*
     89 *                                                                            *
     90 *   Memory Mapped File support.  Platform dependent implementation of        *
     91 *                           functions used by the rest of the implementation.*
     92 *                                                                            *
     93 *----------------------------------------------------------------------------*/
     94 #if MAP_IMPLEMENTATION==MAP_NONE
     95    U_CFUNC UBool
     96    uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
     97        if (U_FAILURE(*status)) {
     98            return false;
     99        }
    100        UDataMemory_init(pData); /* Clear the output struct. */
    101        return false;            /* no file access */
    102    }
    103 
    104    U_CFUNC void uprv_unmapFile(UDataMemory *pData) {
    105        /* nothing to do */
    106    }
    107 #elif MAP_IMPLEMENTATION==MAP_WIN32
    108    U_CFUNC UBool
    109    uprv_mapFile(
    110         UDataMemory *pData,    /* Fill in with info on the result doing the mapping. */
    111                                /*   Output only; any original contents are cleared.  */
    112         const char *path,      /* File path to be opened/mapped.                     */
    113         UErrorCode *status     /* Error status, used to report out-of-memory errors. */
    114         )
    115    {
    116        if (U_FAILURE(*status)) {
    117            return false;
    118        }
    119 
    120        HANDLE map = nullptr;
    121        HANDLE file = INVALID_HANDLE_VALUE;
    122        DWORD fileLength = 0;
    123 
    124        UDataMemory_init(pData); /* Clear the output struct.        */
    125 
    126        /* open the input file */
    127 #if U_PLATFORM_HAS_WINUWP_API == 0
    128        // Note: In the non-UWP code-path (ie: Win32), the value of the path variable might have come from 
    129        // the CRT 'getenv' function, and would be therefore be encoded in the default ANSI code page.
    130        // This means that we can't call the *W version of API below, whereas in the UWP code-path
    131        // there is no 'getenv' call, and thus the string will be only UTF-8/Invariant characters.
    132        file=CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, nullptr,
    133            OPEN_EXISTING,
    134            FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, nullptr);
    135 #else
    136        // Convert from UTF-8 string to UTF-16 string.
    137        wchar_t utf16Path[MAX_PATH];
    138        int32_t pathUtf16Len = 0;
    139        u_strFromUTF8(reinterpret_cast<char16_t*>(utf16Path), static_cast<int32_t>(UPRV_LENGTHOF(utf16Path)), &pathUtf16Len, path, -1, status);
    140 
    141        if (U_FAILURE(*status)) {
    142            return false;
    143        }
    144        if (*status == U_STRING_NOT_TERMINATED_WARNING) {
    145            // Report back an error instead of a warning.
    146            *status = U_BUFFER_OVERFLOW_ERROR;
    147            return false;
    148        }
    149 
    150        file = CreateFileW(utf16Path, GENERIC_READ, FILE_SHARE_READ, nullptr,
    151            OPEN_EXISTING,
    152            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr);
    153 #endif
    154        if (file == INVALID_HANDLE_VALUE) {
    155            // If we failed to open the file due to an out-of-memory error, then we want
    156            // to report that error back to the caller.
    157            if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
    158                *status = U_MEMORY_ALLOCATION_ERROR;
    159            }
    160            return false;
    161        }
    162 
    163        fileLength = GetFileSize(file, nullptr);
    164 
    165        // Note: We use nullptr/nullptr for lpAttributes parameter below.
    166        // This means our handle cannot be inherited and we will get the default security descriptor.
    167        /* create an unnamed Windows file-mapping object for the specified file */
    168        map = CreateFileMappingW(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
    169 
    170        CloseHandle(file);
    171        if (map == nullptr) {
    172            // If we failed to create the mapping due to an out-of-memory error, then 
    173            // we want to report that error back to the caller.
    174            if (HRESULT_FROM_WIN32(GetLastError()) == E_OUTOFMEMORY) {
    175                *status = U_MEMORY_ALLOCATION_ERROR;
    176            }
    177            return false;
    178        }
    179 
    180        /* map a view of the file into our address space */
    181        pData->pHeader = reinterpret_cast<const DataHeader *>(MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0));
    182        if (pData->pHeader == nullptr) {
    183            CloseHandle(map);
    184            return false;
    185        }
    186        pData->map = map;
    187        pData->length = fileLength;
    188 
    189        return true;
    190    }
    191 
    192    U_CFUNC void
    193    uprv_unmapFile(UDataMemory *pData) {
    194        if (pData != nullptr && pData->map != nullptr) {
    195            UnmapViewOfFile(pData->pHeader);
    196            CloseHandle(pData->map);
    197            pData->pHeader = nullptr;
    198            pData->map = nullptr;
    199        }
    200    }
    201 
    202 
    203 
    204 #elif MAP_IMPLEMENTATION==MAP_POSIX
    205    U_CFUNC UBool
    206    uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
    207        int fd;
    208        int length;
    209        struct stat mystat;
    210        void *data;
    211 
    212        if (U_FAILURE(*status)) {
    213            return false;
    214        }
    215 
    216        UDataMemory_init(pData); /* Clear the output struct.        */
    217 
    218        /* determine the length of the file */
    219        if(stat(path, &mystat)!=0 || mystat.st_size<=0) {
    220            return false;
    221        }
    222        length=mystat.st_size;
    223 
    224        /* open the file */
    225        fd=open(path, O_RDONLY);
    226        if(fd==-1) {
    227            return false;
    228        }
    229 
    230        /* get a view of the mapping */
    231 #if U_PLATFORM != U_PF_HPUX
    232        data=mmap(nullptr, length, PROT_READ, MAP_SHARED, fd, 0);
    233 #else
    234        data=mmap(nullptr, length, PROT_READ, MAP_PRIVATE, fd, 0);
    235 #endif
    236        close(fd); /* no longer needed */
    237        if(data==MAP_FAILED) {
    238            // Possibly check the errno value for ENOMEM, and report U_MEMORY_ALLOCATION_ERROR?
    239            return false;
    240        }
    241 
    242        pData->map = (char *)data + length;
    243        pData->pHeader=(const DataHeader *)data;
    244        pData->mapAddr = data;
    245        pData->length = length;
    246 #if U_PLATFORM == U_PF_IPHONE || U_PLATFORM == U_PF_ANDROID
    247    // Apparently supported from Android 23 and higher:
    248    //   https://github.com/ggml-org/llama.cpp/pull/3631
    249    // Checking for the flag itself is safer than checking for __ANDROID_API__.
    250 #   ifdef POSIX_MADV_RANDOM
    251        posix_madvise(data, length, POSIX_MADV_RANDOM);
    252 #   endif
    253 #endif
    254        return true;
    255    }
    256 
    257    U_CFUNC void
    258    uprv_unmapFile(UDataMemory *pData) {
    259        if(pData!=nullptr && pData->map!=nullptr) {
    260            size_t dataLen = (char *)pData->map - (char *)pData->mapAddr;
    261            if(munmap(pData->mapAddr, dataLen)==-1) {
    262            }
    263            pData->pHeader=nullptr;
    264            pData->map=nullptr;
    265            pData->mapAddr=nullptr;
    266        }
    267    }
    268 
    269 
    270 
    271 #elif MAP_IMPLEMENTATION==MAP_STDIO
    272    /* copy of the filestrm.c/T_FileStream_size() implementation */
    273    static int32_t
    274    umap_fsize(FILE *f) {
    275        int32_t savedPos = ftell(f);
    276        int32_t size = 0;
    277 
    278        /*Changes by Bertrand A. D. doesn't affect the current position
    279        goes to the end of the file before ftell*/
    280        fseek(f, 0, SEEK_END);
    281        size = (int32_t)ftell(f);
    282        fseek(f, savedPos, SEEK_SET);
    283        return size;
    284    }
    285 
    286    U_CFUNC UBool
    287    uprv_mapFile(UDataMemory *pData, const char *path, UErrorCode *status) {
    288        FILE *file;
    289        int32_t fileLength;
    290        void *p;
    291 
    292        if (U_FAILURE(*status)) {
    293            return false;
    294        }
    295 
    296        UDataMemory_init(pData); /* Clear the output struct.        */
    297        /* open the input file */
    298        file=fopen(path, "rb");
    299        if(file==nullptr) {
    300            return false;
    301        }
    302 
    303        /* get the file length */
    304        fileLength=umap_fsize(file);
    305        if(ferror(file) || fileLength<=20) {
    306            fclose(file);
    307            return false;
    308        }
    309 
    310        /* allocate the memory to hold the file data */
    311        p=uprv_malloc(fileLength);
    312        if(p==nullptr) {
    313            fclose(file);
    314            *status = U_MEMORY_ALLOCATION_ERROR;
    315            return false;
    316        }
    317 
    318        /* read the file */
    319        if(fileLength!=fread(p, 1, fileLength, file)) {
    320            uprv_free(p);
    321            fclose(file);
    322            return false;
    323        }
    324 
    325        fclose(file);
    326        pData->map=p;
    327        pData->pHeader=(const DataHeader *)p;
    328        pData->mapAddr=p;
    329        pData->length = fileLength;
    330        return true;
    331    }
    332 
    333    U_CFUNC void
    334    uprv_unmapFile(UDataMemory *pData) {
    335        if(pData!=nullptr && pData->map!=nullptr) {
    336            uprv_free(pData->map);
    337            pData->map     = nullptr;
    338            pData->mapAddr = nullptr;
    339            pData->pHeader = nullptr;
    340        }
    341    }
    342 #else
    343 #   error MAP_IMPLEMENTATION is set incorrectly
    344 #endif