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