Home | History | Annotate | Download | only in utils
      1 /* Copyright (C) 2007-2010 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 
     13 /*
     14  * Contains implementation of routines that implement platform-independent
     15  * file I/O.
     16  */
     17 
     18 #include "android/utils/mapfile.h"
     19 
     20 #include "stddef.h"
     21 #include "sys/types.h"
     22 #include "errno.h"
     23 #ifdef  WIN32
     24 #include "windows.h"
     25 #else   // WIN32
     26 #include <sys/mman.h>
     27 #endif  // WIN32
     28 #include <sys/stat.h>
     29 #include <fcntl.h>
     30 #include <unistd.h>
     31 
     32 #include "android/utils/eintr_wrapper.h"
     33 
     34 MapFile*
     35 mapfile_open(const char* path, int oflag, int share_mode)
     36 {
     37 #ifdef WIN32
     38     DWORD win32_share;
     39     DWORD win32_desired_access = GENERIC_READ;
     40     DWORD win32_disposition = OPEN_EXISTING;
     41     DWORD win32_flags;
     42 
     43     /* Convert to Win32 desired access. */
     44     if ((oflag & O_RDWR) == O_RDWR) {
     45         win32_desired_access = GENERIC_READ | GENERIC_WRITE;
     46     } else if ((oflag & O_ACCMODE) == O_RDONLY) {
     47         win32_desired_access = GENERIC_READ;
     48     } else if ((oflag & O_WRONLY) == O_WRONLY) {
     49         win32_desired_access = GENERIC_WRITE;
     50     }
     51 
     52     /* Convert to Win32 sharing. */
     53     win32_share = 0;
     54     if ((share_mode & S_IWRITE) != 0) {
     55         win32_share |= FILE_SHARE_WRITE;
     56     }
     57     if ((share_mode & S_IREAD) != 0) {
     58         win32_share |= FILE_SHARE_READ;
     59     }
     60 
     61     /* Convert to Win32 disposition. */
     62     if ((oflag & O_CREAT) == O_CREAT) {
     63         if ((oflag & O_EXCL) == O_EXCL) {
     64             win32_disposition = CREATE_NEW;
     65         } else {
     66             win32_disposition = OPEN_ALWAYS;
     67         }
     68     } if ((oflag & O_TRUNC) == O_TRUNC) {
     69         win32_desired_access = TRUNCATE_EXISTING;
     70     } else {
     71         win32_disposition = OPEN_EXISTING;
     72     }
     73 
     74     /* Convert to Win32 flags. */
     75     win32_flags = 0;
     76 #if defined(O_DSYNC)
     77     if ((oflag & O_DSYNC) == O_DSYNC ||
     78         (oflag & O_RSYNC) == O_RSYNC ||
     79         (oflag & O_RSYNC) == O_SYNC) {
     80         win32_flags |= FILE_FLAG_WRITE_THROUGH;
     81     }
     82 #endif  // O_DSYNC
     83 
     84     HANDLE file_handle = CreateFile(path, win32_desired_access, win32_share,
     85                                     NULL, win32_disposition, win32_flags, NULL);
     86     if (file_handle == INVALID_HANDLE_VALUE) {
     87         errno = GetLastError();
     88     }
     89 #else   // WIN32
     90     int file_handle = open(path, oflag, share_mode);
     91 #endif  // WIN32
     92 
     93     return (MapFile*)(ptrdiff_t)file_handle;
     94 }
     95 
     96 int
     97 mapfile_close(MapFile* handle)
     98 {
     99 #ifdef WIN32
    100     if (CloseHandle(handle)) {
    101         return 0;
    102     } else {
    103         errno = GetLastError();
    104         return -1;
    105     }
    106 #else   // WIN32
    107     return close((int)(ptrdiff_t)handle);
    108 #endif  // WIN32
    109 }
    110 
    111 ssize_t
    112 mapfile_read(MapFile* handle, void* buf, size_t nbyte)
    113 {
    114 #ifdef WIN32
    115     ssize_t ret_bytes;
    116     DWORD read_bytes;
    117     if (ReadFile(handle, buf, nbyte, &read_bytes, NULL)) {
    118         ret_bytes = (ssize_t)read_bytes;
    119     } else {
    120         errno = GetLastError();
    121         ret_bytes = -1;
    122     }
    123     return ret_bytes;
    124 #else   // WIN32
    125     return HANDLE_EINTR(read((int)(ptrdiff_t)handle, buf, nbyte));
    126 #endif  // WIN32
    127 }
    128 
    129 ssize_t
    130 mapfile_read_at(MapFile* handle, size_t offset, void* buf, size_t nbyte)
    131 {
    132 #ifdef WIN32
    133     LARGE_INTEGER convert;
    134     convert.QuadPart = offset;
    135     if ((SetFilePointer(handle, convert.LowPart, &convert.HighPart,
    136                         FILE_BEGIN) == INVALID_SET_FILE_POINTER) &&
    137             (GetLastError() != NO_ERROR)) {
    138         errno = GetLastError();
    139         return -1;
    140     }
    141     return mapfile_read(handle, buf, nbyte);
    142 #else   // WIN32
    143     ssize_t res = lseek((int)(ptrdiff_t)handle, offset, SEEK_SET);
    144     return res >= 0 ? mapfile_read(handle, buf, nbyte) : res;
    145 #endif  // WIN32
    146 }
    147 
    148 void*
    149 mapfile_map(MapFile* handle,
    150             size_t offset,
    151             size_t size,
    152             int prot,
    153             void** mapped_offset,
    154             size_t* mapped_size)
    155 {
    156     void* mapped_at = NULL;
    157     size_t align_mask;
    158     size_t map_offset;
    159     size_t map_size;
    160 
    161   /* Get the mask for mapping offset alignment. */
    162 #ifdef  WIN32
    163     DWORD win32_prot;
    164     DWORD win32_map;
    165     HANDLE map_handle;
    166     LARGE_INTEGER converter;
    167     SYSTEM_INFO sys_info;
    168     GetSystemInfo(&sys_info);
    169     align_mask = sys_info.dwAllocationGranularity - 1;
    170 #else   // WIN32
    171     align_mask = getpagesize() - 1;
    172 #endif  // WIN32
    173 
    174     /* Adjust mapping offset and mapping size accordingly to
    175      * the mapping alignment requirements. */
    176     map_offset = offset & ~align_mask;
    177     map_size = (size_t)(offset - map_offset + size);
    178 
    179     /* Make sure mapping size doesn't exceed 4G. */
    180     if (map_size < size) {
    181         errno = EFBIG;
    182         return NULL;
    183     }
    184 
    185     /* Map the section. */
    186 #ifdef  WIN32
    187     /* Convert to Win32 page protection and mapping type. */
    188     win32_prot = PAGE_READONLY;
    189     win32_map = FILE_MAP_READ;
    190     if (prot != PROT_NONE) {
    191         if ((prot & (PROT_WRITE | PROT_EXEC)) == 0) {
    192             win32_prot = PAGE_READONLY;
    193             win32_map = FILE_MAP_READ;
    194         } else if ((prot & (PROT_WRITE | PROT_EXEC)) ==
    195                    (PROT_WRITE | PROT_EXEC)) {
    196             win32_prot = PAGE_EXECUTE_READWRITE;
    197             win32_map = FILE_MAP_WRITE;
    198         } else if ((prot & PROT_WRITE) == PROT_WRITE) {
    199             win32_prot = PAGE_READWRITE;
    200             win32_map = FILE_MAP_WRITE;
    201         } else if ((prot & PROT_EXEC) == PROT_EXEC) {
    202             win32_prot = PAGE_EXECUTE_READ;
    203             win32_map = FILE_MAP_READ;
    204         }
    205     }
    206 
    207     converter.QuadPart = map_offset + map_size;
    208     map_handle = CreateFileMapping(handle, NULL, win32_prot,
    209                                    converter.HighPart, converter.LowPart, NULL);
    210     if (map_handle != NULL) {
    211         converter.QuadPart = map_offset;
    212         mapped_at = MapViewOfFile(map_handle, win32_map, converter.HighPart,
    213                                   converter.LowPart, map_size);
    214         /* Memory mapping (if successful) will hold extra references to the
    215         * mapping, so we can close it right after we mapped file view. */
    216         CloseHandle(map_handle);
    217     }
    218     if (mapped_at == NULL) {
    219         errno = GetLastError();
    220         return NULL;
    221     }
    222 #else   // WIN32
    223     mapped_at =
    224         mmap(0, map_size, PROT_READ, MAP_SHARED, (int)(ptrdiff_t)handle, map_offset);
    225     if (mapped_at == MAP_FAILED) {
    226         return NULL;
    227     }
    228 #endif  // WIN32
    229 
    230     *mapped_offset = (char*)mapped_at + (offset - map_offset);
    231     *mapped_size = size;
    232 
    233     return mapped_at;
    234 }
    235 
    236 int
    237 mapfile_unmap(void* mapped_at, size_t len)
    238 {
    239 #ifdef WIN32
    240     if (!UnmapViewOfFile(mapped_at)) {
    241         errno = GetLastError();
    242         return -1;
    243     }
    244     return 0;
    245 #else   // WIN32
    246     return munmap(mapped_at, len);
    247 #endif  // WIN32
    248 }
    249