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 32MapFile* 33mapfile_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 94int 95mapfile_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 109ssize_t 110mapfile_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 131ssize_t 132mapfile_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 150void* 151mapfile_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 238int 239mapfile_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