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