| /* Copyright (C) 2007-2010 The Android Open Source Project |
| ** |
| ** This software is licensed under the terms of the GNU General Public |
| ** License version 2, as published by the Free Software Foundation, and |
| ** may be copied, distributed, and modified under those terms. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU General Public License for more details. |
| */ |
| |
| /* |
| * Contains implementation of routines that implement platform-independent |
| * file I/O. |
| */ |
| |
| #include "stddef.h" |
| #include "sys/types.h" |
| #include "errno.h" |
| #ifdef WIN32 |
| #include "windows.h" |
| #else // WIN32 |
| #include <sys/mman.h> |
| #endif // WIN32 |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| |
| #include "mapfile.h" |
| |
| MapFile* |
| mapfile_open(const char* path, int oflag, int share_mode) |
| { |
| #ifdef WIN32 |
| DWORD win32_share; |
| DWORD win32_desired_access = GENERIC_READ; |
| DWORD win32_disposition = OPEN_EXISTING; |
| DWORD win32_flags; |
| |
| /* Convert to Win32 desired access. */ |
| if ((oflag & O_RDWR) == O_RDWR) { |
| win32_desired_access = GENERIC_READ | GENERIC_WRITE; |
| } else if ((oflag & O_ACCMODE) == O_RDONLY) { |
| win32_desired_access = GENERIC_READ; |
| } else if ((oflag & O_WRONLY) == O_WRONLY) { |
| win32_desired_access = GENERIC_WRITE; |
| } |
| |
| /* Convert to Win32 sharing. */ |
| win32_share = 0; |
| if ((share_mode & S_IWRITE) != 0) { |
| win32_share |= FILE_SHARE_WRITE; |
| } |
| if ((share_mode & S_IREAD) != 0) { |
| win32_share |= FILE_SHARE_READ; |
| } |
| |
| /* Convert to Win32 disposition. */ |
| if ((oflag & O_CREAT) == O_CREAT) { |
| if ((oflag & O_EXCL) == O_EXCL) { |
| win32_disposition = CREATE_NEW; |
| } else { |
| win32_disposition = OPEN_ALWAYS; |
| } |
| } if ((oflag & O_TRUNC) == O_TRUNC) { |
| win32_desired_access = TRUNCATE_EXISTING; |
| } else { |
| win32_disposition = OPEN_EXISTING; |
| } |
| |
| /* Convert to Win32 flags. */ |
| win32_flags = 0; |
| #if defined(O_DSYNC) |
| if ((oflag & O_DSYNC) == O_DSYNC || |
| (oflag & O_RSYNC) == O_RSYNC || |
| (oflag & O_RSYNC) == O_SYNC) { |
| win32_flags |= FILE_FLAG_WRITE_THROUGH; |
| } |
| #endif // O_DSYNC |
| |
| HANDLE file_handle = CreateFile(path, win32_desired_access, win32_share, |
| NULL, win32_disposition, win32_flags, NULL); |
| if (file_handle == INVALID_HANDLE_VALUE) { |
| errno = GetLastError(); |
| } |
| #else // WIN32 |
| int file_handle = open(path, oflag, share_mode); |
| #endif // WIN32 |
| |
| return (MapFile*)(ptrdiff_t)file_handle; |
| } |
| |
| int |
| mapfile_close(MapFile* handle) |
| { |
| #ifdef WIN32 |
| if (CloseHandle(handle)) { |
| return 0; |
| } else { |
| errno = GetLastError(); |
| return -1; |
| } |
| #else // WIN32 |
| return close((int)(ptrdiff_t)handle); |
| #endif // WIN32 |
| } |
| |
| ssize_t |
| mapfile_read(MapFile* handle, void* buf, size_t nbyte) |
| { |
| #ifdef WIN32 |
| ssize_t ret_bytes; |
| DWORD read_bytes; |
| if (ReadFile(handle, buf, nbyte, &read_bytes, NULL)) { |
| ret_bytes = (ssize_t)read_bytes; |
| } else { |
| errno = GetLastError(); |
| ret_bytes = -1; |
| } |
| return ret_bytes; |
| #else // WIN32 |
| ssize_t ret; |
| do { |
| ret = read((int)(ptrdiff_t)handle, buf, nbyte); |
| } while (ret < 0 && errno == EINTR); |
| return ret; |
| #endif // WIN32 |
| } |
| |
| ssize_t |
| mapfile_read_at(MapFile* handle, size_t offset, void* buf, size_t nbyte) |
| { |
| #ifdef WIN32 |
| LARGE_INTEGER convert; |
| convert.QuadPart = offset; |
| if ((SetFilePointer(handle, convert.LowPart, &convert.HighPart, |
| FILE_BEGIN) == INVALID_SET_FILE_POINTER) && |
| (GetLastError() != NO_ERROR)) { |
| errno = GetLastError(); |
| return -1; |
| } |
| return mapfile_read(handle, buf, nbyte); |
| #else // WIN32 |
| ssize_t res = lseek((int)(ptrdiff_t)handle, offset, SEEK_SET); |
| return res >= 0 ? mapfile_read(handle, buf, nbyte) : res; |
| #endif // WIN32 |
| } |
| |
| void* |
| mapfile_map(MapFile* handle, |
| size_t offset, |
| size_t size, |
| int prot, |
| void** mapped_offset, |
| size_t* mapped_size) |
| { |
| void* mapped_at = NULL; |
| size_t align_mask; |
| size_t map_offset; |
| size_t map_size; |
| |
| /* Get the mask for mapping offset alignment. */ |
| #ifdef WIN32 |
| DWORD win32_prot; |
| DWORD win32_map; |
| HANDLE map_handle; |
| LARGE_INTEGER converter; |
| SYSTEM_INFO sys_info; |
| GetSystemInfo(&sys_info); |
| align_mask = sys_info.dwAllocationGranularity - 1; |
| #else // WIN32 |
| align_mask = getpagesize() - 1; |
| #endif // WIN32 |
| |
| /* Adjust mapping offset and mapping size accordingly to |
| * the mapping alignment requirements. */ |
| map_offset = offset & ~align_mask; |
| map_size = (size_t)(offset - map_offset + size); |
| |
| /* Make sure mapping size doesn't exceed 4G. */ |
| if (map_size < size) { |
| errno = EFBIG; |
| return NULL; |
| } |
| |
| /* Map the section. */ |
| #ifdef WIN32 |
| /* Convert to Win32 page protection and mapping type. */ |
| win32_prot = PAGE_READONLY; |
| win32_map = FILE_MAP_READ; |
| if (prot != PROT_NONE) { |
| if ((prot & (PROT_WRITE | PROT_EXEC)) == 0) { |
| win32_prot = PAGE_READONLY; |
| win32_map = FILE_MAP_READ; |
| } else if ((prot & (PROT_WRITE | PROT_EXEC)) == |
| (PROT_WRITE | PROT_EXEC)) { |
| win32_prot = PAGE_EXECUTE_READWRITE; |
| win32_map = FILE_MAP_WRITE; |
| } else if ((prot & PROT_WRITE) == PROT_WRITE) { |
| win32_prot = PAGE_READWRITE; |
| win32_map = FILE_MAP_WRITE; |
| } else if ((prot & PROT_EXEC) == PROT_EXEC) { |
| win32_prot = PAGE_EXECUTE_READ; |
| win32_map = FILE_MAP_READ; |
| } |
| } |
| |
| converter.QuadPart = map_offset + map_size; |
| map_handle = CreateFileMapping(handle, NULL, win32_prot, |
| converter.HighPart, converter.LowPart, NULL); |
| if (map_handle != NULL) { |
| converter.QuadPart = map_offset; |
| mapped_at = MapViewOfFile(map_handle, win32_map, converter.HighPart, |
| converter.LowPart, map_size); |
| /* Memory mapping (if successful) will hold extra references to the |
| * mapping, so we can close it right after we mapped file view. */ |
| CloseHandle(map_handle); |
| } |
| if (mapped_at == NULL) { |
| errno = GetLastError(); |
| return NULL; |
| } |
| #else // WIN32 |
| mapped_at = |
| mmap(0, map_size, PROT_READ, MAP_SHARED, (int)(ptrdiff_t)handle, map_offset); |
| if (mapped_at == MAP_FAILED) { |
| return NULL; |
| } |
| #endif // WIN32 |
| |
| *mapped_offset = (char*)mapped_at + (offset - map_offset); |
| *mapped_size = size; |
| |
| return mapped_at; |
| } |
| |
| int |
| mapfile_unmap(void* mapped_at, size_t len) |
| { |
| #ifdef WIN32 |
| if (!UnmapViewOfFile(mapped_at)) { |
| errno = GetLastError(); |
| return -1; |
| } |
| return 0; |
| #else // WIN32 |
| return munmap(mapped_at, len); |
| #endif // WIN32 |
| } |