/*****************************************************************************\ * 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 #include #define MAR_ALL (MAR_READ | MAR_WRITE) typedef struct mar_impl { struct mar_mmap mmap_; int fd_, prot_; size_t size_; }* mar_impl_t; static int mar_toprot_(int* to, int from) { int prot = 0; if (from & ~MAR_ALL) goto fail; if (MAR_READ == (from & MAR_READ)) prot |= PROT_READ; if (MAR_WRITE == (from & MAR_WRITE)) prot |= PROT_WRITE; if (!prot) prot = PROT_NONE; *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; if (!len) len = impl->size_ - offset; if (MAP_FAILED == (addr = mmap(NULL, len, impl->prot_, MAP_SHARED, impl->fd_, (off_t)offset))) return -1; impl->mmap_.addr_ = addr; impl->mmap_.len_ = len; return 0; } static int mar_dofreemmap_(mar_impl_t impl) { if (impl->mmap_.addr_) return munmap(impl->mmap_.addr_, impl->mmap_.len_); 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; int prot; size_t size; if (-1 == mar_toprot_(&prot, 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->size_ = size; 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 && -1 == munmap(addr, impl->mmap_.len_)) return -1; if (impl->size_ < (offset + len)) { 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_; return msync(impl->mmap_.addr_, impl->mmap_.len_, MS_SYNC); } 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) { return getpagesize(); } MAR_EXTERN size_t mar_pagesize_(void) { return getpagesize(); }