/*****************************************************************************\ * Copyright (c) 2004 Mark Aylett * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, sublicense, and/or sell copies of the Software, and to permit * * persons to whom the Software is furnished to do so, subject to the * * following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * * USE OR OTHER DEALINGS IN THE SOFTWARE. * \*****************************************************************************/ #include "mar_file_c.h" #include "mar_windows_c.h" #include #define MAR_ALL (MAR_READ | MAR_WRITE) typedef struct mar_impl { struct mar_mmap mmap_; int fd_; DWORD prot_, access_; size_t size_; HANDLE mapping_; }* mar_impl_t; static int mar_toaccess_(DWORD* to, int from) { DWORD access = 0; if (from & ~MAR_ALL) goto fail; if (MAR_READ == (from & MAR_READ)) access |= FILE_MAP_READ; if (MAR_WRITE == (from & MAR_WRITE)) access |= FILE_MAP_WRITE; *to = access; return 0; fail: errno = EINVAL; return -1; } static int mar_toprot_(DWORD* to, int from) { DWORD prot = 0; if (from & ~MAR_ALL) goto fail; if (MAR_READ != (from & MAR_READ)) goto fail; if (MAR_WRITE == (from & MAR_WRITE)) prot = PAGE_READWRITE; else prot = PAGE_READONLY; *to = prot; return 0; fail: errno = EINVAL; return -1; } static int mar_verify_(size_t size, size_t offset, size_t len) { /** * An empty file cannot be mapped, in addition, the size * to be mapped should not be greater than the file size. */ if (!size || size < (offset + len)) { errno = EINVAL; return -1; } /** * The offset if specified must occur on an allocation * size boundary. */ if (offset && (offset % mar_granularity_())) { errno = EINVAL; return -1; } return 0; } static int mar_docreatemmap_(mar_impl_t impl, size_t offset, size_t len) { void* addr; HANDLE mapping; DWORD err; long file = _get_osfhandle(impl->fd_); if (-1 == file) { errno = EINVAL; return -1; } if (!len) len = impl->size_ - offset; mapping = impl->mapping_; if (INVALID_HANDLE_VALUE == mapping) { if (!(mapping = CreateFileMapping((HANDLE)file, NULL, impl->prot_, 0, impl->size_, NULL))) { err = GetLastError(); goto fail1; } } if (!(addr = MapViewOfFile(mapping, impl->access_, 0, offset, len))) { err = GetLastError(); goto fail2; } impl->mmap_.addr_ = addr; impl->mmap_.len_ = len; impl->mapping_ = mapping; return 0; fail2: if (INVALID_HANDLE_VALUE == impl->mapping_) CloseHandle(mapping); fail1: mar_maperror_(err); return -1; } static int mar_dofreemmap_(mar_impl_t impl) { DWORD err = 0; if (impl->mmap_.addr_ && !UnmapViewOfFile(impl->mmap_.addr_)) err = GetLastError(); if (INVALID_HANDLE_VALUE != impl->mapping_ && !CloseHandle(impl->mapping_) && !err) err = GetLastError(); if (err) { mar_maperror_(err); return -1; } return 0; } MAR_EXTERN int mar_freemmap_(mar_mmap_t mmap_) { mar_impl_t impl = (mar_impl_t)mmap_; int ret = mar_dofreemmap_(impl); free(impl); return ret; } MAR_EXTERN mar_mmap_t mar_createmmap_(int fd, size_t offset, size_t len, int flags) { mar_impl_t impl; DWORD prot, access; size_t size; if (-1 == mar_toprot_(&prot, flags)) return NULL; if (-1 == mar_toaccess_(&access, flags)) return NULL; if (-1 == mar_filesize_(fd, &size)) return NULL; if (-1 == mar_verify_(size, offset, len)) return NULL; if (!(impl = (mar_impl_t) malloc(sizeof(struct mar_impl)))) { return NULL; } impl->mmap_.addr_ = NULL; impl->mmap_.len_ = 0; impl->fd_ = fd; impl->prot_ = prot; impl->access_ = access; impl->size_ = size; impl->mapping_ = INVALID_HANDLE_VALUE; if (-1 == mar_docreatemmap_(impl, offset, len)) { free(impl); return NULL; } return (mar_mmap_t)impl; } MAR_EXTERN int mar_remmap_(mar_mmap_t mmap_, size_t offset, size_t len) { mar_impl_t impl = (mar_impl_t)mmap_; void* addr = impl->mmap_.addr_; impl->mmap_.addr_ = NULL; if (addr && !UnmapViewOfFile(addr)) { mar_maperror_(GetLastError()); return -1; } if (impl->size_ < (offset + len)) { HANDLE mapping = impl->mapping_; impl->mapping_ = INVALID_HANDLE_VALUE; if (INVALID_HANDLE_VALUE != mapping && !CloseHandle(mapping)) { mar_maperror_(GetLastError()); return -1; } if (-1 == mar_filesize_(impl->fd_, &impl->size_)) return -1; } if (-1 == mar_verify_(impl->size_, offset, len)) return -1; return mar_docreatemmap_(impl, offset, len); } MAR_EXTERN int mar_syncmmap_(mar_mmap_t mmap_) { mar_impl_t impl = (mar_impl_t)mmap_; if (!FlushViewOfFile(impl->mmap_.addr_, impl->mmap_.len_)) { mar_maperror_(GetLastError()); return -1; } return 0; } MAR_EXTERN size_t mar_mmapsize_(mar_mmap_t mmap_) { mar_impl_t impl = (mar_impl_t)mmap_; return impl->size_; } MAR_EXTERN size_t mar_granularity_(void) { SYSTEM_INFO info; GetSystemInfo(&info); return info.dwAllocationGranularity; } MAR_EXTERN size_t mar_pagesize_(void) { SYSTEM_INFO info; GetSystemInfo(&info); return info.dwPageSize; }