ClamAV is an open source (GPLv2) anti-virus toolkit.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
clamav/libclamav/fmap.c

733 lines
20 KiB

16 years ago
/*
16 years ago
* Copyright (C) 2009 Sourcefire, Inc.
16 years ago
*
* Authors: aCaB <acab@clamav.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
/* an mmap "replacement" which doesn't suck */
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
16 years ago
#include <string.h>
#ifdef HAVE_UNISTD_H
16 years ago
#include <unistd.h>
#endif
15 years ago
#ifdef ANONYMOUS_MAP
16 years ago
#ifdef HAVE_SYS_MMAN_H
16 years ago
#include <sys/mman.h>
16 years ago
#endif
#endif
15 years ago
#include <errno.h>
16 years ago
#ifdef C_LINUX
16 years ago
#include <pthread.h>
#endif
16 years ago
16 years ago
#include "others.h"
#include "cltypes.h"
16 years ago
static inline unsigned int fmap_align_items(unsigned int sz, unsigned int al);
static inline unsigned int fmap_align_to(unsigned int sz, unsigned int al);
static inline unsigned int fmap_which_page(fmap_t *m, size_t at);
16 years ago
#ifndef _WIN32
/* vvvvv POSIX STUFF BELOW vvvvv */
static ssize_t pread_cb(void *handle, void *buf, size_t count, off_t offset);
/* pread proto here in order to avoid the use of XOPEN and BSD_SOURCE
which may in turn prevent some mmap constants to be defined */
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) {
unsigned int pages, mapsz, hdrsz;
unsigned short dumb = 1;
int pgsz = cli_getpagesize();
struct stat st;
fmap_t *m;
void *handle = (void*)(ssize_t)fd;
*empty = 0;
if(fstat(fd, &st)) {
cli_warnmsg("fmap: fstat failed\n");
return NULL;
}
if(!len) len = st.st_size - offset; /* bound checked later */
if(!len) {
cli_dbgmsg("fmap: attempted void mapping\n");
*empty = 1;
return NULL;
}
if(!CLI_ISCONTAINED(0, st.st_size, offset, len)) {
cli_warnmsg("fmap: attempted oof mapping\n");
return NULL;
}
m = cl_fmap_open_handle((void*)(ssize_t)fd, offset, len, pread_cb, 1);
if (!m)
return NULL;
m->mtime = st.st_mtime;
m->handle_is_fd = 1;
return m;
}
#else
/* vvvvv WIN32 STUFF BELOW vvvvv */
static void unmap_win32(fmap_t *m) { /* WIN32 */
UnmapViewOfFile(m->data);
CloseHandle(m->mh);
free((void *)m);
}
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) { /* WIN32 */
unsigned int pages, mapsz, hdrsz;
int pgsz = cli_getpagesize();
struct stat st;
fmap_t *m;
const void *data;
HANDLE fh;
HANDLE mh;
*empty = 0;
if(fstat(fd, &st)) {
cli_warnmsg("fmap: fstat failed\n");
return NULL;
}
if(offset < 0 || offset != fmap_align_to(offset, pgsz)) {
cli_warnmsg("fmap: attempted mapping with unaligned offset\n");
return NULL;
}
if(!len) len = st.st_size - offset; /* bound checked later */
if(!len) {
cli_dbgmsg("fmap: attempted void mapping\n");
*empty = 1;
return NULL;
}
if(!CLI_ISCONTAINED(0, st.st_size, offset, len)) {
cli_warnmsg("fmap: attempted oof mapping\n");
return NULL;
}
pages = fmap_align_items(len, pgsz);
hdrsz = fmap_align_to(sizeof(fmap_t), pgsz);
if((fh = (HANDLE)_get_osfhandle(fd)) == INVALID_HANDLE_VALUE) {
cli_errmsg("fmap: cannot get a valid handle for descriptor %d\n", fd);
return NULL;
}
if(!(mh = CreateFileMapping(m->fh, NULL, PAGE_READONLY, (DWORD)((len>>31)>>1), (DWORD)len, NULL))) {
cli_errmsg("fmap: cannot create a map of descriptor %d\n", fd);
CloseHandle(fh);
return NULL;
}
if(!(data = MapViewOfFile(m->mh, FILE_MAP_READ, (DWORD)((offset>>31)>>1), (DWORD)(offset), len))) {
cli_errmsg("fmap: cannot map file descriptor %d\n", fd);
CloseHandle(mh);
CloseHandle(fh);
return NULL;
}
if(!(m = cl_fmap_open_memory(data, len))) {
cli_errmsg("fmap: canot allocate fmap_t\n", fd);
CloseHandle(mh);
CloseHandle(fh);
return NULL;
}
m->handle = (void*)(ssize_t)fd;
m->handle_is_fd = 1;
m->fh = fh;
m->mh = mh;
m->unmap = unmap_win32;
return m;
}
#endif /* _WIN32 */
/* vvvvv SHARED STUFF BELOW vvvvv */
#define FM_MASK_COUNT 0x3fffffff
#define FM_MASK_PAGED 0x40000000
#define FM_MASK_SEEN 0x80000000
#define FM_MASK_LOCKED FM_MASK_SEEN
/* 2 high bits:
00 - not seen - not paged - N/A
01 - N/A - paged - not locked
10 - seen - not paged - N/A
11 - N/A - paged - locked
*/
16 years ago
/* FIXME: tune this stuff */
16 years ago
#define UNPAGE_THRSHLD_LO 4*1024*1024
#define UNPAGE_THRSHLD_HI 8*1024*1024
16 years ago
#define READAHEAD_PAGES 8
15 years ago
#if defined(ANONYMOUS_MAP) && defined(C_LINUX) && defined(CL_THREAD_SAFE)
/*
WORKAROUND
Relieve some stress on mmap_sem.
When mmap_sem is heavily hammered, the scheduler
tends to fail to wake us up properly.
*/
16 years ago
pthread_mutex_t fmap_mutex = PTHREAD_MUTEX_INITIALIZER;
#define fmap_lock pthread_mutex_lock(&fmap_mutex)
#define fmap_unlock pthread_mutex_unlock(&fmap_mutex);
#else
#define fmap_lock
#define fmap_unlock
#endif
#ifndef MADV_DONTFORK
#define MADV_DONTFORK 0
#endif
#define fmap_bitmap (&m->placeholder_for_bitmap)
16 years ago
static const void *handle_need(fmap_t *m, size_t at, size_t len, int lock);
static void handle_unneed_off(fmap_t *m, size_t at, size_t len);
static const void *handle_need_offstr(fmap_t *m, size_t at, size_t len_hint);
static const void *handle_gets(fmap_t *m, char *dst, size_t *at, size_t max_len);
static void unmap_mmap(fmap_t *m);
static void unmap_malloc(fmap_t *m);
extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len,
clcb_pread pread_cb, int use_aging)
{
unsigned int pages, mapsz, hdrsz;
cl_fmap_t *m;
int pgsz = cli_getpagesize();
16 years ago
if(offset < 0 || offset != fmap_align_to(offset, pgsz)) {
16 years ago
cli_warnmsg("fmap: attempted mapping with unaligned offset\n");
return NULL;
}
if(!len) {
15 years ago
cli_dbgmsg("fmap: attempted void mapping\n");
16 years ago
return NULL;
}
if (offset >= len) {
16 years ago
cli_warnmsg("fmap: attempted oof mapping\n");
return NULL;
}
16 years ago
pages = fmap_align_items(len, pgsz);
hdrsz = fmap_align_to(sizeof(fmap_t) + (pages-1) * sizeof(uint32_t), pgsz); /* fmap_t includes 1 bitmap slot, hence (pages-1) */
16 years ago
mapsz = pages * pgsz + hdrsz;
#ifndef ANONYMOUS_MAP
use_aging = 0;
#endif
15 years ago
#ifdef ANONYMOUS_MAP
if (use_aging) {
fmap_lock;
if ((m = (fmap_t *)mmap(NULL, mapsz, PROT_READ | PROT_WRITE, MAP_PRIVATE|/*FIXME: MAP_POPULATE is ~8% faster but more memory intensive */ANONYMOUS_MAP, -1, 0)) == MAP_FAILED) {
m = NULL;
} else {
#if HAVE_MADVISE
madvise((void *)m, mapsz, MADV_RANDOM|MADV_DONTFORK);
#endif /* madvise */
/* fault the header while we still have the lock - we DO context switch here a lot here :@ */
memset(fmap_bitmap, 0, sizeof(uint32_t) * pages);
}
fmap_unlock;
}
15 years ago
#endif /* ANONYMOUS_MAP */
if (!use_aging) {
m = (fmap_t *)cli_malloc(mapsz);
memset(m, 0, hdrsz);
}
16 years ago
if(!m) {
cli_warnmsg("fmap: map allocation failed\n");
16 years ago
return NULL;
}
m->handle = handle;
m->pread_cb = pread_cb;
m->aging = use_aging;
16 years ago
m->offset = offset;
m->len = len;
m->pages = pages;
m->hdrsz = hdrsz;
m->pgsz = pgsz;
m->paged = 0;
m->dont_cache_flag = 0;
m->unmap = use_aging ? unmap_mmap : unmap_malloc;
m->need = handle_need;
m->need_offstr = handle_need_offstr;
m->gets = handle_gets;
m->unneed_off = handle_unneed_off;
16 years ago
return m;
}
static ssize_t pread_cb(void *handle, void *buf, size_t count, off_t offset)
{
return pread((int)(ssize_t)handle, buf, count, offset);
}
static void fmap_aging(fmap_t *m) {
15 years ago
#ifdef ANONYMOUS_MAP
if(!m->aging) return;
if(m->paged * m->pgsz > UNPAGE_THRSHLD_HI) { /* we alloc'd too much */
unsigned int i, avail = 0, freeme[2048], maxavail = MIN(sizeof(freeme)/sizeof(*freeme), m->paged - UNPAGE_THRSHLD_LO / m->pgsz) - 1;
for(i=0; i<m->pages; i++) {
uint32_t s = fmap_bitmap[i];
if((s & (FM_MASK_PAGED | FM_MASK_LOCKED)) == FM_MASK_PAGED ) {
/* page is paged and not locked: dec age */
if(s & FM_MASK_COUNT) fmap_bitmap[i]--;
/* and make it available for unpaging */
if(!avail) {
freeme[0] = i;
avail++;
} else {
/* Insert sort onto a stack'd array - same performance as quickselect */
unsigned int insert_to = MIN(maxavail, avail) - 1, age = fmap_bitmap[i] & FM_MASK_COUNT;
if(avail <= maxavail || (fmap_bitmap[freeme[maxavail]] & FM_MASK_COUNT) > age) {
while((fmap_bitmap[freeme[insert_to]] & FM_MASK_COUNT) > age) {
freeme[insert_to + 1] = freeme[insert_to];
if(!insert_to--) break;
}
freeme[insert_to + 1] = i;
if(avail <= maxavail) avail++;
}
}
}
}
if(avail) { /* at least one page is paged and not locked */
char *lastpage = NULL;
char *firstpage = NULL;
for(i=0; i<avail; i++) {
char *pptr = (char *)m + freeme[i] * m->pgsz + m->hdrsz;
/* we mark the page as seen */
fmap_bitmap[freeme[i]] = FM_MASK_SEEN;
/* and we mmap the page over so the kernel knows there's nothing good in there */
/* reduce number of mmap calls: if pages are adjacent only do 1 mmap call */
if (lastpage && pptr == lastpage) {
lastpage = pptr + m->pgsz;
continue;
}
if (!lastpage) {
firstpage = pptr;
lastpage = pptr + m->pgsz;
continue;
}
fmap_lock;
if(mmap(firstpage, lastpage - firstpage, PROT_READ | PROT_WRITE, MAP_FIXED|MAP_PRIVATE|ANONYMOUS_MAP, -1, 0) == MAP_FAILED)
cli_dbgmsg("fmap_aging: kernel hates you\n");
fmap_unlock;
firstpage = pptr;
lastpage = pptr + m->pgsz;
}
if (lastpage) {
fmap_lock;
if(mmap(firstpage, lastpage - firstpage, PROT_READ | PROT_WRITE, MAP_FIXED|MAP_PRIVATE|ANONYMOUS_MAP, -1, 0) == MAP_FAILED)
cli_dbgmsg("fmap_aging: kernel hates you\n");
fmap_unlock;
}
m->paged -= avail;
}
}
16 years ago
#endif
}
static int fmap_readpage(fmap_t *m, unsigned int first_page, unsigned int count, unsigned int lock_count) {
15 years ago
size_t readsz = 0, eintr_off;
15 years ago
char *pptr = NULL, err[256];
uint32_t s;
16 years ago
unsigned int i, page = first_page, force_read = 0;
fmap_lock;
for(i=0; i<count; i++) { /* prefault */
/* Not worth checking if the page is already paged, just ping each */
/* Also not worth reusing the loop below */
volatile char faultme;
faultme = ((char *)m)[(first_page+i) * m->pgsz + m->hdrsz];
16 years ago
}
fmap_unlock;
16 years ago
for(i=0; i<=count; i++, page++) {
int lock;
if(lock_count) {
lock_count--;
lock = 1;
} else lock = 0;
if(i == count) {
/* we count one page too much to flush pending reads */
if(!pptr) return 0; /* if we have any */
force_read = 1;
} else if((s=fmap_bitmap[page]) & FM_MASK_PAGED) {
16 years ago
/* page already paged */
if(lock) {
/* we want locking */
if(s & FM_MASK_LOCKED) {
/* page already locked */
s &= FM_MASK_COUNT;
if(s == FM_MASK_COUNT) { /* lock count already at max: fial! */
cli_errmsg("fmap_readpage: lock count exceeded\n");
return 1;
}
/* acceptable lock count: inc lock count */
fmap_bitmap[page]++;
16 years ago
} else /* page not currently locked: set lock count = 1 */
fmap_bitmap[page] = 1 | FM_MASK_LOCKED | FM_MASK_PAGED;
16 years ago
} else {
/* we don't want locking */
if(!(s & FM_MASK_LOCKED)) {
/* page is not locked: we reset aging to max */
fmap_bitmap[page] = FM_MASK_PAGED | FM_MASK_COUNT;
}
}
16 years ago
if(!pptr) continue;
force_read = 1;
}
16 years ago
if(force_read) {
/* we have some pending reads to perform */
if (m->handle_is_fd) {
unsigned int j;
int _fd = (int)(ssize_t)m->handle;
for(j=first_page; j<page; j++) {
if(fmap_bitmap[j] & FM_MASK_SEEN) {
/* page we've seen before: check mtime */
struct stat st;
char err[256];
if(fstat(_fd, &st)) {
cli_warnmsg("fmap_readpage: fstat failed: %s\n", cli_strerror(errno, err, sizeof(err)));
return 1;
}
if(m->mtime != st.st_mtime) {
cli_warnmsg("fmap_readpage: file changed as we read it\n");
return 1;
}
break;
16 years ago
}
}
}
15 years ago
eintr_off = 0;
while(readsz) {
15 years ago
ssize_t got;
got=m->pread_cb(m->handle, pptr, readsz, eintr_off + m->offset + first_page * m->pgsz);
15 years ago
if(got < 0 && errno == EINTR)
continue;
if(got > 0) {
pptr += got;
eintr_off += got;
readsz -= got;
continue;
}
if(got <0)
cli_errmsg("fmap_readpage: pread error: %s\n", cli_strerror(errno, err, sizeof(err)));
else
cli_warnmsg("fmap_readpage: pread fail: asked for %lu bytes @ offset %lu, got %lu\n", (long unsigned int)readsz, (long unsigned int)(eintr_off + m->offset + first_page * m->pgsz), (long unsigned int)got);
16 years ago
return 1;
}
15 years ago
16 years ago
pptr = NULL;
force_read = 0;
16 years ago
readsz = 0;
continue;
}
16 years ago
/* page is not already paged */
if(!pptr) {
/* set a new start for pending reads if we don't have one */
pptr = (char *)m + page * m->pgsz + m->hdrsz;
first_page = page;
}
16 years ago
if((page == m->pages - 1) && (m->len % m->pgsz))
readsz += m->len % m->pgsz;
else
readsz += m->pgsz;
if(lock) /* lock requested: set paged, lock page and set lock count to 1 */
fmap_bitmap[page] = FM_MASK_PAGED | FM_MASK_LOCKED | 1;
16 years ago
else /* no locking: set paged and set aging to max */
fmap_bitmap[page] = FM_MASK_PAGED | FM_MASK_COUNT;
16 years ago
m->paged++;
}
return 0;
}
static const void *handle_need(fmap_t *m, size_t at, size_t len, int lock) {
unsigned int first_page, last_page, lock_count;
char *ret;
if(!len)
return NULL;
15 years ago
if(!CLI_ISCONTAINED(0, m->len, at, len))
return NULL;
16 years ago
fmap_aging(m);
first_page = fmap_which_page(m, at);
last_page = fmap_which_page(m, at + len - 1);
16 years ago
lock_count = (lock!=0) * (last_page-first_page+1);
16 years ago
#ifdef READAHED_PAGES
last_page += READAHED_PAGES;
if(last_page >= m->pages) last_page = m->pages - 1;
#endif
16 years ago
if(fmap_readpage(m, first_page, last_page-first_page+1, lock_count))
return NULL;
ret = (char *)m;
ret += at + m->hdrsz;
16 years ago
return (void *)ret;
}
static void fmap_unneed_page(fmap_t *m, unsigned int page) {
uint32_t s = fmap_bitmap[page];
16 years ago
if((s & (FM_MASK_PAGED | FM_MASK_LOCKED)) == (FM_MASK_PAGED | FM_MASK_LOCKED)) {
/* page is paged and locked: check lock count */
s &= FM_MASK_COUNT;
if(s > 1) /* locked more than once: dec lock count */
fmap_bitmap[page]--;
else if (s == 1) /* only one lock left: unlock and begin aging */
fmap_bitmap[page] = FM_MASK_COUNT | FM_MASK_PAGED;
else
cli_errmsg("fmap_unneed: inconsistent map state\n");
return;
}
cli_warnmsg("fmap_unneed: unneed on a unlocked page\n");
return;
}
static void handle_unneed_off(fmap_t *m, size_t at, size_t len) {
unsigned int i, first_page, last_page;
if(!m->aging) return;
if(!len) {
cli_warnmsg("fmap_unneed: attempted void unneed\n");
return;
}
if(!CLI_ISCONTAINED(0, m->len, at, len)) {
cli_warnmsg("fmap: attempted oof unneed\n");
return;
}
16 years ago
first_page = fmap_which_page(m, at);
last_page = fmap_which_page(m, at + len - 1);
for(i=first_page; i<=last_page; i++) {
fmap_unneed_page(m, i);
}
}
static void unmap_mmap(fmap_t *m)
{
15 years ago
#ifdef ANONYMOUS_MAP
size_t len = m->pages * m->pgsz + m->hdrsz;
fmap_lock;
munmap((void *)m, len);
fmap_unlock;
16 years ago
#endif
16 years ago
}
static void unmap_malloc(fmap_t *m) {
free((void *)m);
}
static const void *handle_need_offstr(fmap_t *m, size_t at, size_t len_hint) {
unsigned int i, first_page, last_page;
16 years ago
void *ptr = (void *)((char *)m + m->hdrsz + at);
if(!len_hint || len_hint > m->len - at)
len_hint = m->len - at;
if(!CLI_ISCONTAINED(0, m->len, at, len_hint))
return NULL;
fmap_aging(m);
first_page = fmap_which_page(m, at);
last_page = fmap_which_page(m, at + len_hint - 1);
for(i=first_page; i<=last_page; i++) {
char *thispage = (char *)m + m->hdrsz + i * m->pgsz;
unsigned int scanat, scansz;
if(fmap_readpage(m, i, 1, 1)) {
last_page = i-1;
break;
}
if(i == first_page) {
scanat = at % m->pgsz;
16 years ago
scansz = MIN(len_hint, m->pgsz - scanat);
} else {
scanat = 0;
16 years ago
scansz = MIN(len_hint, m->pgsz);
}
16 years ago
len_hint -= scansz;
if(memchr(&thispage[scanat], 0, scansz))
return ptr;
}
for(i=first_page; i<=last_page; i++)
fmap_unneed_page(m, i);
return NULL;
}
16 years ago
static const void *handle_gets(fmap_t *m, char *dst, size_t *at, size_t max_len) {
16 years ago
unsigned int i, first_page, last_page;
char *src = (void *)((char *)m + m->hdrsz + *at), *endptr = NULL;
size_t len = MIN(max_len-1, m->len - *at), fullen = len;
if(!len || !CLI_ISCONTAINED(0, m->len, *at, len))
16 years ago
return NULL;
fmap_aging(m);
first_page = fmap_which_page(m, *at);
last_page = fmap_which_page(m, *at + len - 1);
for(i=first_page; i<=last_page; i++) {
char *thispage = (char *)m + m->hdrsz + i * m->pgsz;
unsigned int scanat, scansz;
if(fmap_readpage(m, i, 1, 0))
return NULL;
if(i == first_page) {
scanat = *at % m->pgsz;
scansz = MIN(len, m->pgsz - scanat);
} else {
scanat = 0;
scansz = MIN(len, m->pgsz);
}
len -= scansz;
if((endptr = memchr(&thispage[scanat], '\n', scansz))) {
endptr++;
break;
}
}
if(endptr) {
memcpy(dst, src, endptr - src);
dst[endptr - src] = '\0';
*at += endptr - src;
} else {
memcpy(dst, src, fullen);
dst[fullen] = '\0';
*at += fullen;
}
return dst;
}
/* vvvvv MEMORY STUFF BELOW vvvvv */
static const void *mem_need(fmap_t *m, size_t at, size_t len, int lock);
static void mem_unneed_off(fmap_t *m, size_t at, size_t len);
static const void *mem_need_offstr(fmap_t *m, size_t at, size_t len_hint);
static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len);
static void unmap_none(fmap_t *m) {}
extern cl_fmap_t *cl_fmap_open_memory(const void *start, size_t len)
{
cl_fmap_t *m = cli_calloc(1, sizeof(*m));
if (!m) {
cli_warnmsg("fmap: map allocation failed\n");
return NULL;
}
m->data = start;
m->len = len;
m->unmap = unmap_none;
m->need = mem_need;
m->need_offstr = mem_need_offstr;
m->gets = mem_gets;
m->unneed_off = mem_unneed_off;
}
static const void *mem_need(fmap_t *m, size_t at, size_t len, int lock) { /* WIN32 */
15 years ago
if(!CLI_ISCONTAINED(0, m->len, at, len))
return NULL;
15 years ago
if(!len)
return NULL;
return (void *)((char *)m->data + at);
}
static void mem_unneed_off(fmap_t *m, size_t at, size_t len) {}
static const void *mem_need_offstr(fmap_t *m, size_t at, size_t len_hint) {
char *ptr = (char *)m->data + at;
if(!len_hint || len_hint > m->len - at)
len_hint = m->len - at;
if(!CLI_ISCONTAINED(0, m->len, at, len_hint))
return NULL;
if(memchr(ptr, 0, len_hint))
return (void *)ptr;
return NULL;
}
static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len) {
char *src = (char *)m->data + *at, *endptr = NULL;
size_t len = MIN(max_len-1, m->len - *at);
if(!len || !CLI_ISCONTAINED(0, m->len, *at, len))
return NULL;
16 years ago
if((endptr = memchr(src, '\n', len))) {
endptr++;
memcpy(dst, src, endptr - src);
dst[endptr - src] = '\0';
*at += endptr - src;
} else {
memcpy(dst, src, len);
dst[len] = '\0';
*at += len;
}
return dst;
}
15 years ago
fmap_t *fmap(int fd, off_t offset, size_t len) {
int unused;
return fmap_check_empty(fd, offset, len, &unused);
}
16 years ago
static inline unsigned int fmap_align_items(unsigned int sz, unsigned int al) {
return sz / al + (sz % al != 0);
}
static inline unsigned int fmap_align_to(unsigned int sz, unsigned int al) {
return al * fmap_align_items(sz, al);
}
static inline unsigned int fmap_which_page(fmap_t *m, size_t at) {
return at / m->pgsz;
}
int fmap_fd(fmap_t *m)
{
int fd;
if (!m->handle_is_fd) {
cli_warnmsg("fmap: trying to retrieve descriptor from something that is not\n");
return -1;
}
fd = (int)(ssize_t)m->handle;
lseek(fd, 0, SEEK_SET);
return fd;
}