Chris Johns 0382b6863b Fix Windows build issues.
Fix biulding the mmap Windows code.
Fix installing the files for Windows.
2015-10-19 09:06:49 +11:00

249 lines
5.9 KiB
C

/*-
* Copyright (c) 2011, 2015 Chris Johns <chrisj@rtems.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Basic mmap/munmap set of functions that allows software that needs to use
* these functions to work without changing. Currently only the basic read
* has been tested.
*
* The basic was taken from the implementation in Python 3.x by Sam Rushing
* <rushing@nightmare.com>.
*/
#ifndef __WIN32__
#error "Wrong OS; only for WIN32"
#endif
#include <errno.h>
#include <stdint.h>
#include <io.h>
#include <windows.h>
/*
* Bring in the local mman.h header to make sure the interface is in sync.
*/
#include <sys/mman.h>
/*
* The data for each map. Maintained as a list. If performance is important maybe
* some other container can be used.
*/
typedef struct mmap_data_s
{
struct mmap_data_s* next;
void* data;
HANDLE file_handle;
HANDLE map_handle;
size_t size;
off_t offset;
} mmap_data;
/*
* Head of the map list.
*/
static mmap_data* map_head;
void*
mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset)
{
mmap_data* map = NULL;
DWORD flProtect;
DWORD dwDesiredAccess;
HANDLE fh = 0;
DWORD dwErr = 0;
DWORD size_lo;
DWORD size_hi;
DWORD off_lo;
DWORD off_hi;
uint64_t size = 0;
if ((fd == 0) || (fd == -1))
return MAP_FAILED;
/*
* Not implemented. Patches welcome.
*/
if (prot & PROT_EXEC)
return MAP_FAILED;
/*
* Map the protection.
*/
if ((prot & PROT_READ) == PROT_READ)
{
flProtect = PAGE_READONLY;
dwDesiredAccess = FILE_MAP_READ;
}
if ((prot & PROT_WRITE) == PROT_WRITE)
{
flProtect = PAGE_WRITECOPY;
dwDesiredAccess = FILE_MAP_WRITE;
}
if ((prot & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE))
{
flProtect = PAGE_READWRITE;
dwDesiredAccess = FILE_MAP_WRITE;
}
fh = (HANDLE) (intptr_t) _get_osfhandle (fd);
if (fh == (HANDLE) -1)
return MAP_FAILED;
/*
* Win9x appears to need us seeked to zero.
*/
lseek (fd, 0, SEEK_SET);
/*
* Allocate the space to handle the mapping.
*/
map = malloc (sizeof (mmap_data));
if (!map)
return MAP_FAILED;
map->next = NULL;
map->data = NULL;
map->file_handle = fh;
map->map_handle = NULL;
map->offset = offset;
if (len == 0)
{
DWORD low;
DWORD high;
low = GetFileSize (fh, &high);
/*
* Low might just happen to have the value INVALID_FILE_SIZE; so we need to
* check the last error also.
*/
if ((low == INVALID_FILE_SIZE) && (dwErr = GetLastError()) != NO_ERROR)
{
free (map);
return MAP_FAILED;
}
size = (((uint64_t) high) << 32) + low;
if (offset >= size)
{
free (map);
return MAP_FAILED;
}
if (offset - size > (size_t) -1LL)
/* Map area too large to fit in memory */
map->size = (size_t) -1;
else
map->size = (size_t) (size - offset);
}
else
{
map->size = len;
size = offset + len;
}
size_hi = (DWORD)(size >> 32);
size_lo = (DWORD)(size & 0xFFFFFFFF);
off_hi = (DWORD)(0);
off_lo = (DWORD)(offset & 0xFFFFFFFF);
/*
* For files, it would be sufficient to pass 0 as size. For anonymous maps,
* we have to pass the size explicitly.
*/
map->map_handle = CreateFileMapping (map->file_handle,
NULL,
flProtect,
size_hi,
size_lo,
NULL);
if (!map->map_handle)
{
free (map);
return MAP_FAILED;
}
map->data = (char *) MapViewOfFileEx (map->map_handle,
dwDesiredAccess,
off_hi,
off_lo,
map->size,
addr);
if (!map->data)
{
CloseHandle (map->map_handle);
free (map);
return MAP_FAILED;
}
/*
* Add to the list.
*/
map->next = map_head;
map_head = map;
return map->data;
}
int
munmap (void* addr, size_t len)
{
mmap_data* map = map_head;
mmap_data** prev_next = &map_head;
/*
* Find the map and remove from the list.
*/
while (map)
{
if (map->data == addr)
{
*prev_next = map->next;
break;
}
prev_next = &map->next;
map = map->next;
}
if (!map)
{
errno = EINVAL;
return -1;
}
if (map->data != NULL)
UnmapViewOfFile (map->data);
if (map->map_handle != NULL)
CloseHandle (map->map_handle);
free (map);
errno = 0;
return 0;
}