1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/memory/virtual.c
Alexandre Julliard ebfc0fee51 Release 980628
Sun Jun 28 18:37:02 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [if1632/signal.c] [miscemu/instr.c] [memory/virtual.c]
	Moved page-fault handling to INSTR_EmulateInstruction.

	* [scheduler/thread.c]
	Added locking and check for own thread in Suspend/ResumeThread.

Sat Jun 27 21:25:21 1998  Ulrich Weigand <weigand@informatik.uni-erlangen.de>

	* [objects/dib.c] [objects/bitmap.c] [objects/oembitmap.c] 
	  [graphics/x11drv/bitblt.c] [include/bitmap.h]
	Improved DIB section handling using page fault handlers.
	(Note: This patch includes code contributed by Matthew J. Francis.)

	* [memory/virtual.c] [if1632/signal.c] [include/global.h]
	Page Fault handler support added.

	* [if1632/signal.c] [loader/signal.c] [tools/build.c] [misc/system.c]
	  [misc/winsock_dns.c] [include/sig_context.h] [include/thread.h]
	16-bit %fs handling improved: Always preserve 16-bit %fs value,
	always restore 32-bit %fs value for signal handlers.

	* [if1632/thunk.c] [loader/module.c] [misc/callback.c] [windows/user.c]
	  [loader/ne/resource.c] [include/callback.h] [include/module.h]
	  [if1632/kernel.spec] [if1632/wprocs.spec]
	Resource Handler function pointer stored as 16-bit SEGPTR.

	* [loader/task.c] [windows/win.c] [windows/winpos.c] [if1632/user.spec]
	  [if1632/kernel.spec] [loader/ne/module.c]
	Some minor incompatibilities fixed (Win32s relies on those):
	GetExePtr, IsWindow16 should set ES on return; WINPOS_SendNCCalcSize
	should cope with having the WINDOWPOS structure trashed;
	the OFSTRUCT in the NE module image should be placed *last*.

	* [include/windows.h]
	Missing prototype for FlushViewOfFile.

	* [loader/task.c]
	Bugfix: Command line should *not* start with a blank.
	
	* [loader/ne/segment.c]
	Bugfix: Fixups to offset 0 were never applied.

	* [misc/lstr.c]
	Use debugstr_a in OutputDebugString16.

	* [msdos/dpmi.c]
	Stub for int 31 BL=2f AX=7a20 (NetWare: Get VLM Call Address) added.

	* [msdos/int21.c]
	Stub for int 21 AX=440d CL=6f (get drive map information) added.

Fri Jun 26 18:08:30 1998  Rein Klazes <rklazes@casema.net>

	* [windows/winpos.c]
	Fix small buglet that mixed up maximized and minimized windows.

	* [include/x11drv.h] [objects/dc.c] [graphics/x11drv/pen.c]
	  [graphics/x11drv/graphics.c]
	Fix some bugs with lines joining styles. Draws rectangles
	with thick pens now correctly.

Fri Jun 26 16:22:23 1998  James Juran <jrj120@psu.edu>

	* [misc/shell.c]
	Fixed bug I introduced last release in InternalExtractIcon.

	* [win32/file.c]
	Added documentation for CreateFile32A.

	* [documentation/wine.man]
	Updated manpage.	

	* [ChangeLog]
	Added my entry from last release.

Fri Jun 26 13:33:30 1998  Huw D M Davies <daviesh@abacus.physics.ox.ac.uk>

	* [graphics/psdrv/*] [if1632/wineps.spec] [include/psdrv.h]
	  [include/print.h] [objects/gdiobj.c]
	First stages of an internal Postscript driver. See
	graphics/psdrv/README . Should print text (badly) from win3.1 notepad,
	write and winword6.

	* [documentation/printing]
	Some notes on printing.

	* [controls/edit.c]
	Strip off WS_BORDER in WM_NCREATE, edit draws its own rectangle.
	EC_USEFONTINFO seems to be used as a left/right value for EM_SETMARGINS
	and not as an action as the docs say. This actually makes more sense.
	Scroll the caret back to zero after a WM_SETTEXT.

Fri Jun 26 10:56:25 1998  Marcus Meissner <marcus@jet.franken.de>

	* [if1632/snoop.c]
	Added win16 inter-dll snooping.

	* [win32/ordinals.c]
	KERNEL_485 is GetProcessDword.

	* [include/xmalloc.h][include/bitmap.h][misc/xmalloc.c]
	Added xcalloc so we 0 initialize XImages. 
	Fixes/Hides the 'junk around MOPYFish'.

	* [misc/ntdll.c]
	Some stubs added.

Thu Jun 25 15:22:43 1998  Adrian Harvey <adrian@select.com.au>

	* [scheduler/thread.c] 
	Implemented SuspendThread and ResumeThread.

Thu Jun 25 00:55:03 1998  Peter Hunnisett <hunnise@nortel.ca>

	* [include/debug.h,dplay.h,dsound.h][multimedia/dsound.c,dplay.c]
	  [relay32/dplayx.spec,dplay.spec][multimedia/Makefile.in]
	  [documentation/status/directplay]
	Added preliminary support for DirectPlay & DirectPlayLobby. Moved the
	preliminary stubs put in the dsound files into two new files
	dplay.h and dplay.c.
	Added new debug channel (dplay) for this.
	Created new document to keep track of implementation.

	* [include/winioctl.h][win32/device.c]
	Added some framework in DeviceIoControl to, in the future, support
	the "builtin" windows dwIoControlCodes. Added new header file
	winioctl.h . 

	* [multimedia/mmsystem.c]
	Added slightly improved debugging information for PlaySound.

Wed Jun 24 12:00:00 1998  Juergen Schmied <juergen.schmied@metronet.de> 

	* [files/profile.c][graphics/x11drv/xfont.c][loader/module.c]
	Changed lstrcmpi32A to strcasecmp, lstrncmpi32A to strncasecmp,
	lstrcpy32A to strcpy, lstrlen32A to strlen, lstrcmp32A to strcmp
	because it's not necessary to support locale on such places.
	It causes a huge overhead and even fails sometimes 

	* [include/oleauto.h][include/winerror.h]
	Added some ole-related constants.

	* [misc/shell.c]
	SHELL32_DllGetClassObject, SHGetSpecialFolderLocation,
	SHGetPathFromIDList improved the stubs

	* [ole/folders.c]
	IShellFolder* functions rewrote the stubs so don't crash and give
	something sensible back, started implementation of.

	* [ole/typelib.c][relay32/oleaut32.spec]
	LoadTypeLib32, RegisterTypeLib stub.

	* [ole/ole2nls.c]
	Fixed a buffer overrun in CompareString32A.
	Test for a bad pointer in LCMapString32A (happens
	in winhlp32 while building a index for searching). 

	* [relay32/oleaut32.spec] [ole/typelib.c]
	Added stub for LoadTypeLib (ole32) to make excel95 happy.

Tue Jun 23 22:47:09 1998  Alex Priem <alexp@sci.kun.nl>

	* [files/profile.c] [relay32/kernel32.spec]
	Added WritePrivateProfileStructA, GetPrivateProfileStructA,
	GetPrivateProfileSectionNames16.

Tue Jun 23 01:34:43 1998  Pascal Cuoq <pcuoq@ens-lyon.fr>

	* [ole/ole2nls.c]
	GetStringTypeEx32A: Implemented CT_CTYPE2 and CT_CTYPE3 cases.
	LCMapString32A: Map final '\0' for '\0'-terminated strings.

	* [misc/shellord.c] [files/profile.c] [graphics/driver.c] 
	  [loader/module.c] [msdos/int21.c] [windows/driver.c] [files/drive.c]
	Changed lstrcmpi32A -> strcasecmp.  Should be OK in these places.

Sat Jun 20 23:40:00 1998  Bertho Stultiens <bertho@akhphd.au.dk>

	* [tools/wrc/]
	Wrc version 1.0.2 (20-Jun-1998). Please revert to 
	the file tools/wrc/CHANGES for details.

Sat Jun 20 14:58:00 1998  Marcel Baur  <mbaur@g26.ethz.ch>

	* [ole/ole2nls.c] [ole/nls/*]
	Added the first 57 nls files, most are not yet complete.

Wed Jun 17 11:16:54 1998  David Luyer <luyer@ucs.uwa.edu.au>

	* [relay32/relay386.c] [if1632/relay.c]
	Move debug_relay_(include|exclude)_list handling into
	seperate function RELAY_ShowDebugmsgsRelay().  Include
	checking of this for 16 bit calls (originally only
	32-bit calls).

	* [relay32/snoop.c] [misc/main.c]
	Add debug_snoop_(include|exclude)_list as per the relay stuff.
	Fix typo and add information on -debugmsg +/-relay=... in
	help on -debugmsg.  Refer to availability of snoop too.

Tue Jun 10 22:00:18 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [controls/header.c][include/header.h][include/commctrl.h]
	Added owner draw support.

	* [windows/nonclient.c][windows/sysmetics.c]
	Fixed menu bar height for Win95 look.
	Split NC_AdjustRect95() into NC_AdjustRectOuter95() and
	NC_AdjustRectInner95 to fix a menu bar bug.
	Improved Win95 look.

	* [controls/progress.c]
	Improved drawing code. Borders will be drawn by non-client code.

	* [controls/updown.c]
	Changed memory allocation and fixed some bugs.

	* [controls/toolbar.c]
	Fixed TB_BUTTONSTRUCTSIZE bug in MFC programs.
	Several improvements.

	* [misc/shell.c]
	Added stub for BrowseForFoldersA().

	* [misc/shellord.c]
	Added stub for SHELL32_147().

	* [controls/comctl32undoc.c]
	Minor changes.

	* [documentation/common_controls]
	New File: Documentation about development status, undocumented
	features and functions of the common controls.
1998-06-28 18:40:26 +00:00

1434 lines
41 KiB
C

/*
* Win32 virtual memory functions
*
* Copyright 1997 Alexandre Julliard
*/
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/mman.h>
#include "winbase.h"
#include "winerror.h"
#include "file.h"
#include "heap.h"
#include "process.h"
#include "xmalloc.h"
#include "global.h"
#include "debug.h"
#ifndef MS_SYNC
#define MS_SYNC 0
#endif
/* File mapping */
typedef struct
{
K32OBJ header;
DWORD size_high;
DWORD size_low;
FILE_OBJECT *file;
BYTE protect;
} FILE_MAPPING;
/* File view */
typedef struct _FV
{
struct _FV *next; /* Next view */
struct _FV *prev; /* Prev view */
UINT32 base; /* Base address */
UINT32 size; /* Size in bytes */
UINT32 flags; /* Allocation flags */
UINT32 offset; /* Offset from start of mapped file */
FILE_MAPPING *mapping; /* File mapping */
HANDLERPROC handlerProc; /* Fault handler */
LPVOID handlerArg; /* Fault handler argument */
BYTE protect; /* Protection for all pages at allocation time */
BYTE prot[1]; /* Protection byte for each page */
} FILE_VIEW;
/* Per-page protection byte values */
#define VPROT_READ 0x01
#define VPROT_WRITE 0x02
#define VPROT_EXEC 0x04
#define VPROT_WRITECOPY 0x08
#define VPROT_GUARD 0x10
#define VPROT_NOCACHE 0x20
#define VPROT_COMMITTED 0x40
/* Per-view flags */
#define VFLAG_SYSTEM 0x01
/* Conversion from VPROT_* to Win32 flags */
static const BYTE VIRTUAL_Win32Flags[16] =
{
PAGE_NOACCESS, /* 0 */
PAGE_READONLY, /* READ */
PAGE_READWRITE, /* WRITE */
PAGE_READWRITE, /* READ | WRITE */
PAGE_EXECUTE, /* EXEC */
PAGE_EXECUTE_READ, /* READ | EXEC */
PAGE_EXECUTE_READWRITE, /* WRITE | EXEC */
PAGE_EXECUTE_READWRITE, /* READ | WRITE | EXEC */
PAGE_WRITECOPY, /* WRITECOPY */
PAGE_WRITECOPY, /* READ | WRITECOPY */
PAGE_WRITECOPY, /* WRITE | WRITECOPY */
PAGE_WRITECOPY, /* READ | WRITE | WRITECOPY */
PAGE_EXECUTE_WRITECOPY, /* EXEC | WRITECOPY */
PAGE_EXECUTE_WRITECOPY, /* READ | EXEC | WRITECOPY */
PAGE_EXECUTE_WRITECOPY, /* WRITE | EXEC | WRITECOPY */
PAGE_EXECUTE_WRITECOPY /* READ | WRITE | EXEC | WRITECOPY */
};
static FILE_VIEW *VIRTUAL_FirstView;
#ifdef __i386__
/* These are always the same on an i386, and it will be faster this way */
# define page_mask 0xfff
# define page_shift 12
# define granularity_mask 0xffff
#else
static UINT32 page_shift;
static UINT32 page_mask;
static UINT32 granularity_mask; /* Allocation granularity (usually 64k) */
#endif /* __i386__ */
#define ROUND_ADDR(addr) \
((UINT32)(addr) & ~page_mask)
#define ROUND_SIZE(addr,size) \
(((UINT32)(size) + ((UINT32)(addr) & page_mask) + page_mask) & ~page_mask)
static void VIRTUAL_DestroyMapping( K32OBJ *obj );
const K32OBJ_OPS MEM_MAPPED_FILE_Ops =
{
/* Object cannot be waited upon, so we don't need these (except destroy) */
NULL, /* signaled */
NULL, /* satisfied */
NULL, /* add_wait */
NULL, /* remove_wait */
NULL, /* read */
NULL, /* write */
VIRTUAL_DestroyMapping /* destroy */
};
#define VIRTUAL_DEBUG_DUMP_VIEW(view) \
if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
/***********************************************************************
* VIRTUAL_GetProtStr
*/
static const char *VIRTUAL_GetProtStr( BYTE prot )
{
static char buffer[6];
buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-';
buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-';
buffer[2] = (prot & VPROT_READ) ? 'r' : '-';
buffer[3] = (prot & VPROT_WRITE) ?
((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-';
buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-';
buffer[5] = 0;
return buffer;
}
/***********************************************************************
* VIRTUAL_DumpView
*/
static void VIRTUAL_DumpView( FILE_VIEW *view )
{
UINT32 i, count;
UINT32 addr = view->base;
BYTE prot = view->prot[0];
DUMP( "View: %08x - %08x%s",
view->base, view->base + view->size - 1,
(view->flags & VFLAG_SYSTEM) ? " (system)" : "" );
if (view->mapping && view->mapping->file)
DUMP( " %s @ %08x\n", view->mapping->file->unix_name, view->offset );
else
DUMP( " (anonymous)\n");
for (count = i = 1; i < view->size >> page_shift; i++, count++)
{
if (view->prot[i] == prot) continue;
DUMP( " %08x - %08x %s\n",
addr, addr + (count << page_shift) - 1,
VIRTUAL_GetProtStr(prot) );
addr += (count << page_shift);
prot = view->prot[i];
count = 0;
}
if (count)
DUMP( " %08x - %08x %s\n",
addr, addr + (count << page_shift) - 1,
VIRTUAL_GetProtStr(prot) );
}
/***********************************************************************
* VIRTUAL_Dump
*/
void VIRTUAL_Dump(void)
{
FILE_VIEW *view = VIRTUAL_FirstView;
DUMP( "\nDump of all virtual memory views:\n\n" );
while (view)
{
VIRTUAL_DumpView( view );
view = view->next;
}
}
/***********************************************************************
* VIRTUAL_FindView
*
* Find the view containing a given address.
*
* RETURNS
* View: Success
* NULL: Failure
*/
static FILE_VIEW *VIRTUAL_FindView(
UINT32 addr /* [in] Address */
) {
FILE_VIEW *view = VIRTUAL_FirstView;
while (view)
{
if (view->base > addr) return NULL;
if (view->base + view->size > addr) return view;
view = view->next;
}
return NULL;
}
/***********************************************************************
* VIRTUAL_CreateView
*
* Create a new view and add it in the linked list.
*/
static FILE_VIEW *VIRTUAL_CreateView( UINT32 base, UINT32 size, UINT32 offset,
UINT32 flags, BYTE vprot,
FILE_MAPPING *mapping )
{
FILE_VIEW *view, *prev;
/* Create the view structure */
assert( !(base & page_mask) );
assert( !(size & page_mask) );
size >>= page_shift;
if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL;
view->base = base;
view->size = size << page_shift;
view->flags = flags;
view->offset = offset;
view->mapping = mapping;
view->protect = vprot;
memset( view->prot, vprot, size );
/* Insert it in the linked list */
if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base))
{
view->next = VIRTUAL_FirstView;
view->prev = NULL;
if (view->next) view->next->prev = view;
VIRTUAL_FirstView = view;
}
else
{
prev = VIRTUAL_FirstView;
while (prev->next && (prev->next->base < base)) prev = prev->next;
view->next = prev->next;
view->prev = prev;
if (view->next) view->next->prev = view;
prev->next = view;
}
VIRTUAL_DEBUG_DUMP_VIEW( view );
return view;
}
/***********************************************************************
* VIRTUAL_DeleteView
* Deletes a view.
*
* RETURNS
* None
*/
static void VIRTUAL_DeleteView(
FILE_VIEW *view /* [in] View */
) {
FILE_munmap( (void *)view->base, 0, view->size );
if (view->next) view->next->prev = view->prev;
if (view->prev) view->prev->next = view->next;
else VIRTUAL_FirstView = view->next;
if (view->mapping) K32OBJ_DecCount( &view->mapping->header );
free( view );
}
/***********************************************************************
* VIRTUAL_GetUnixProt
*
* Convert page protections to protection for mmap/mprotect.
*/
static int VIRTUAL_GetUnixProt( BYTE vprot )
{
int prot = 0;
if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
{
if (vprot & VPROT_READ) prot |= PROT_READ;
if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
}
return prot;
}
/***********************************************************************
* VIRTUAL_GetWin32Prot
*
* Convert page protections to Win32 flags.
*
* RETURNS
* None
*/
static void VIRTUAL_GetWin32Prot(
BYTE vprot, /* [in] Page protection flags */
DWORD *protect, /* [out] Location to store Win32 protection flags */
DWORD *state /* [out] Location to store mem state flag */
) {
if (protect) {
*protect = VIRTUAL_Win32Flags[vprot & 0x0f];
if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;
if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
}
if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;
}
/***********************************************************************
* VIRTUAL_GetProt
*
* Build page protections from Win32 flags.
*
* RETURNS
* Value of page protection flags
*/
static BYTE VIRTUAL_GetProt(
DWORD protect /* [in] Win32 protection flags */
) {
BYTE vprot;
switch(protect & 0xff)
{
case PAGE_READONLY:
vprot = VPROT_READ;
break;
case PAGE_READWRITE:
vprot = VPROT_READ | VPROT_WRITE;
break;
case PAGE_WRITECOPY:
vprot = VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
break;
case PAGE_EXECUTE:
vprot = VPROT_EXEC;
break;
case PAGE_EXECUTE_READ:
vprot = VPROT_EXEC | VPROT_READ;
break;
case PAGE_EXECUTE_READWRITE:
vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE | VPROT_WRITECOPY;
break;
case PAGE_EXECUTE_WRITECOPY:
vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;
break;
case PAGE_NOACCESS:
default:
vprot = 0;
break;
}
if (protect & PAGE_GUARD) vprot |= VPROT_GUARD;
if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE;
return vprot;
}
/***********************************************************************
* VIRTUAL_SetProt
*
* Change the protection of a range of pages.
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
static BOOL32 VIRTUAL_SetProt(
FILE_VIEW *view, /* [in] Pointer to view */
UINT32 base, /* [in] Starting address */
UINT32 size, /* [in] Size in bytes */
BYTE vprot /* [in] Protections to use */
) {
TRACE(virtual, "%08x-%08x %s\n",
base, base + size - 1, VIRTUAL_GetProtStr( vprot ) );
if (mprotect( (void *)base, size, VIRTUAL_GetUnixProt(vprot) ))
return FALSE; /* FIXME: last error */
memset( view->prot + ((base - view->base) >> page_shift),
vprot, size >> page_shift );
VIRTUAL_DEBUG_DUMP_VIEW( view );
return TRUE;
}
/***********************************************************************
* VIRTUAL_CheckFlags
*
* Check that all pages in a range have the given flags.
*
* RETURNS
* TRUE: They do
* FALSE: They do not
*/
static BOOL32 VIRTUAL_CheckFlags(
UINT32 base, /* [in] Starting address */
UINT32 size, /* [in] Size in bytes */
BYTE flags /* [in] Flags to check for */
) {
FILE_VIEW *view;
UINT32 page;
if (!size) return TRUE;
if (!(view = VIRTUAL_FindView( base ))) return FALSE;
if (view->base + view->size < base + size) return FALSE;
page = (base - view->base) >> page_shift;
size = ROUND_SIZE( base, size ) >> page_shift;
while (size--) if ((view->prot[page++] & flags) != flags) return FALSE;
return TRUE;
}
/***********************************************************************
* VIRTUAL_Init
*/
BOOL32 VIRTUAL_Init(void)
{
#ifndef __i386__
DWORD page_size;
# ifdef HAVE_GETPAGESIZE
page_size = getpagesize();
# else
# ifdef __svr4__
page_size = sysconf(_SC_PAGESIZE);
# else
# error Cannot get the page size on this platform
# endif
# endif
page_mask = page_size - 1;
granularity_mask = 0xffff; /* hard-coded for now */
/* Make sure we have a power of 2 */
assert( !(page_size & page_mask) );
page_shift = 0;
while ((1 << page_shift) != page_size) page_shift++;
#endif /* !__i386__ */
#ifdef linux
{
/* Do not use stdio here since it may temporarily change the size
* of some segments (ie libc6 adds 0x1000 per open FILE)
*/
int fd = open ("/proc/self/maps", O_RDONLY);
if (fd >= 0)
{
char buffer[512]; /* line might be rather long in 2.1 */
for (;;)
{
int start, end, offset;
char r, w, x, p;
BYTE vprot = VPROT_COMMITTED;
char * ptr = buffer;
int count = sizeof(buffer);
while (1 == read(fd, ptr, 1) && *ptr != '\n' && --count > 0)
ptr++;
if (*ptr != '\n') break;
*ptr = '\0';
sscanf( buffer, "%x-%x %c%c%c%c %x",
&start, &end, &r, &w, &x, &p, &offset );
if (r == 'r') vprot |= VPROT_READ;
if (w == 'w') vprot |= VPROT_WRITE;
if (x == 'x') vprot |= VPROT_EXEC;
if (p == 'p') vprot |= VPROT_WRITECOPY;
VIRTUAL_CreateView( start, end - start, 0,
VFLAG_SYSTEM, vprot, NULL );
}
close (fd);
}
}
#endif /* linux */
return TRUE;
}
/***********************************************************************
* VIRTUAL_GetPageSize
*/
DWORD VIRTUAL_GetPageSize(void)
{
return 1 << page_shift;
}
/***********************************************************************
* VIRTUAL_GetGranularity
*/
DWORD VIRTUAL_GetGranularity(void)
{
return granularity_mask + 1;
}
/***********************************************************************
* VIRTUAL_SetFaultHandler
*/
BOOL32 VIRTUAL_SetFaultHandler( LPVOID addr, HANDLERPROC proc, LPVOID arg )
{
FILE_VIEW *view;
if (!(view = VIRTUAL_FindView((UINT32)addr))) return FALSE;
view->handlerProc = proc;
view->handlerArg = arg;
return TRUE;
}
/***********************************************************************
* VIRTUAL_HandleFault
*/
BOOL32 VIRTUAL_HandleFault(LPVOID addr)
{
FILE_VIEW *view = VIRTUAL_FindView((UINT32)addr);
if (view && view->handlerProc)
return view->handlerProc(view->handlerArg, addr);
return FALSE;
}
/***********************************************************************
* VirtualAlloc (KERNEL32.548)
* Reserves or commits a region of pages in virtual address space
*
* RETURNS
* Base address of allocated region of pages
* NULL: Failure
*/
LPVOID WINAPI VirtualAlloc(
LPVOID addr, /* [in] Address of region to reserve or commit */
DWORD size, /* [in] Size of region */
DWORD type, /* [in] Type of allocation */
DWORD protect /* [in] Type of access protection */
) {
FILE_VIEW *view;
UINT32 base, ptr, view_size;
BYTE vprot;
TRACE(virtual, "%08x %08lx %lx %08lx\n",
(UINT32)addr, size, type, protect );
/* Round parameters to a page boundary */
if (size > 0x7fc00000) /* 2Gb - 4Mb */
{
SetLastError( ERROR_OUTOFMEMORY );
return NULL;
}
if (addr)
{
if (type & MEM_RESERVE) /* Round down to 64k boundary */
base = ((UINT32)addr + granularity_mask) & ~granularity_mask;
else
base = ROUND_ADDR( addr );
size = (((UINT32)addr + size + page_mask) & ~page_mask) - base;
if (base + size < base) /* Disallow wrap-around */
{
SetLastError( ERROR_INVALID_PARAMETER );
return NULL;
}
}
else
{
base = 0;
size = (size + page_mask) & ~page_mask;
}
if (type & MEM_TOP_DOWN) {
/* FIXME: MEM_TOP_DOWN allocates the largest possible address.
* Is there _ANY_ way to do it with UNIX mmap()?
*/
WARN(virtual,"MEM_TOP_DOWN ignored\n");
type &= ~MEM_TOP_DOWN;
}
/* Compute the protection flags */
if (!(type & (MEM_COMMIT | MEM_RESERVE)) ||
(type & ~(MEM_COMMIT | MEM_RESERVE)))
{
SetLastError( ERROR_INVALID_PARAMETER );
return NULL;
}
if (type & MEM_COMMIT)
vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
else vprot = 0;
/* Reserve the memory */
if ((type & MEM_RESERVE) || !base)
{
view_size = size + (base ? 0 : granularity_mask + 1);
ptr = (UINT32)FILE_dommap( NULL, (LPVOID)base, 0, view_size, 0, 0,
VIRTUAL_GetUnixProt( vprot ), MAP_PRIVATE );
if (ptr == (UINT32)-1)
{
SetLastError( ERROR_OUTOFMEMORY );
return NULL;
}
if (!base)
{
/* Release the extra memory while keeping the range */
/* starting on a 64k boundary. */
if (ptr & granularity_mask)
{
UINT32 extra = granularity_mask + 1 - (ptr & granularity_mask);
FILE_munmap( (void *)ptr, 0, extra );
ptr += extra;
view_size -= extra;
}
if (view_size > size)
FILE_munmap( (void *)(ptr + size), 0, view_size - size );
}
else if (ptr != base)
{
/* We couldn't get the address we wanted */
FILE_munmap( (void *)ptr, 0, view_size );
SetLastError( ERROR_INVALID_ADDRESS );
return NULL;
}
if (!(view = VIRTUAL_CreateView( ptr, size, 0, 0, vprot, NULL )))
{
FILE_munmap( (void *)ptr, 0, size );
SetLastError( ERROR_OUTOFMEMORY );
return NULL;
}
VIRTUAL_DEBUG_DUMP_VIEW( view );
return (LPVOID)ptr;
}
/* Commit the pages */
if (!(view = VIRTUAL_FindView( base )) ||
(base + size > view->base + view->size))
{
SetLastError( ERROR_INVALID_PARAMETER );
return NULL;
}
if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL;
return (LPVOID)base;
}
/***********************************************************************
* VirtualFree (KERNEL32.550)
* Release or decommits a region of pages in virtual address space.
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL32 WINAPI VirtualFree(
LPVOID addr, /* [in] Address of region of committed pages */
DWORD size, /* [in] Size of region */
DWORD type /* [in] Type of operation */
) {
FILE_VIEW *view;
UINT32 base;
TRACE(virtual, "%08x %08lx %lx\n",
(UINT32)addr, size, type );
/* Fix the parameters */
size = ROUND_SIZE( addr, size );
base = ROUND_ADDR( addr );
if (!(view = VIRTUAL_FindView( base )) ||
(base + size > view->base + view->size))
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
/* Compute the protection flags */
if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
/* Free the pages */
if (type == MEM_RELEASE)
{
if (size || (base != view->base))
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
VIRTUAL_DeleteView( view );
return TRUE;
}
/* Decommit the pages */
return VIRTUAL_SetProt( view, base, size, 0 );
}
/***********************************************************************
* VirtualLock (KERNEL32.551)
* Locks the specified region of virtual address space
*
* NOTE
* Always returns TRUE
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL32 WINAPI VirtualLock(
LPVOID addr, /* [in] Address of first byte of range to lock */
DWORD size /* [in] Number of bytes in range to lock */
) {
return TRUE;
}
/***********************************************************************
* VirtualUnlock (KERNEL32.556)
* Unlocks a range of pages in the virtual address space
*
* NOTE
* Always returns TRUE
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL32 WINAPI VirtualUnlock(
LPVOID addr, /* [in] Address of first byte of range */
DWORD size /* [in] Number of bytes in range */
) {
return TRUE;
}
/***********************************************************************
* VirtualProtect (KERNEL32.552)
* Changes the access protection on a region of committed pages
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL32 WINAPI VirtualProtect(
LPVOID addr, /* [in] Address of region of committed pages */
DWORD size, /* [in] Size of region */
DWORD new_prot, /* [in] Desired access protection */
LPDWORD old_prot /* [out] Address of variable to get old protection */
) {
FILE_VIEW *view;
UINT32 base, i;
BYTE vprot, *p;
TRACE(virtual, "%08x %08lx %08lx\n",
(UINT32)addr, size, new_prot );
/* Fix the parameters */
size = ROUND_SIZE( addr, size );
base = ROUND_ADDR( addr );
if (!(view = VIRTUAL_FindView( base )) ||
(base + size > view->base + view->size))
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
/* Make sure all the pages are committed */
p = view->prot + ((base - view->base) >> page_shift);
for (i = size >> page_shift; i; i--, p++)
{
if (!(*p & VPROT_COMMITTED))
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
}
VIRTUAL_GetWin32Prot( view->prot[0], old_prot, NULL );
vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
return VIRTUAL_SetProt( view, base, size, vprot );
}
/***********************************************************************
* VirtualProtectEx (KERNEL32.553)
* Changes the access protection on a region of committed pages in the
* virtual address space of a specified process
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL32 WINAPI VirtualProtectEx(
HANDLE32 handle, /* [in] Handle of process */
LPVOID addr, /* [in] Address of region of committed pages */
DWORD size, /* [in] Size of region */
DWORD new_prot, /* [in] Desired access protection */
LPDWORD old_prot /* [out] Address of variable to get old protection */
) {
BOOL32 ret = FALSE;
PDB32 *pdb = PROCESS_GetPtr( handle, PROCESS_VM_OPERATION );
if (pdb)
{
if (pdb == PROCESS_Current())
ret = VirtualProtect( addr, size, new_prot, old_prot );
else
ERR(virtual,"Unsupported on other process\n");
K32OBJ_DecCount( &pdb->header );
}
return ret;
}
/***********************************************************************
* VirtualQuery (KERNEL32.554)
* Provides info about a range of pages in virtual address space
*
* RETURNS
* Number of bytes returned in information buffer
*/
DWORD WINAPI VirtualQuery(
LPCVOID addr, /* [in] Address of region */
LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
DWORD len /* [in] Size of buffer */
) {
FILE_VIEW *view = VIRTUAL_FirstView;
UINT32 base = ROUND_ADDR( addr );
UINT32 alloc_base = 0;
UINT32 size = 0;
/* Find the view containing the address */
for (;;)
{
if (!view)
{
size = 0xffff0000 - alloc_base;
break;
}
if (view->base > base)
{
size = view->base - alloc_base;
view = NULL;
break;
}
if (view->base + view->size > base)
{
alloc_base = view->base;
size = view->size;
break;
}
alloc_base = view->base + view->size;
view = view->next;
}
/* Fill the info structure */
if (!view)
{
info->State = MEM_FREE;
info->Protect = 0;
info->AllocationProtect = 0;
info->Type = 0;
}
else
{
BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
for (size = base - alloc_base; size < view->size; size += page_mask+1)
if (view->prot[size >> page_shift] != vprot) break;
info->AllocationProtect = view->protect;
info->Type = MEM_PRIVATE; /* FIXME */
}
info->BaseAddress = (LPVOID)base;
info->AllocationBase = (LPVOID)alloc_base;
info->RegionSize = size - (base - alloc_base);
return sizeof(*info);
}
/***********************************************************************
* VirtualQueryEx (KERNEL32.555)
* Provides info about a range of pages in virtual address space of a
* specified process
*
* RETURNS
* Number of bytes returned in information buffer
*/
DWORD WINAPI VirtualQueryEx(
HANDLE32 handle, /* [in] Handle of process */
LPCVOID addr, /* [in] Address of region */
LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
DWORD len /* [in] Size of buffer */
) {
DWORD ret = len;
PDB32 *pdb = PROCESS_GetPtr( handle, PROCESS_QUERY_INFORMATION );
if (pdb)
{
if (pdb == PROCESS_Current())
ret = VirtualQuery( addr, info, len );
else
ERR(virtual,"Unsupported on other process\n");
K32OBJ_DecCount( &pdb->header );
}
return ret;
}
/***********************************************************************
* IsBadReadPtr32 (KERNEL32.354)
*
* RETURNS
* FALSE: Process has read access to entire block
* TRUE: Otherwise
*/
BOOL32 WINAPI IsBadReadPtr32(
LPCVOID ptr, /* Address of memory block */
UINT32 size /* Size of block */
) {
return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
VPROT_READ | VPROT_COMMITTED );
}
/***********************************************************************
* IsBadWritePtr32 (KERNEL32.357)
*
* RETURNS
* FALSE: Process has write access to entire block
* TRUE: Otherwise
*/
BOOL32 WINAPI IsBadWritePtr32(
LPVOID ptr, /* [in] Address of memory block */
UINT32 size /* [in] Size of block in bytes */
) {
return !VIRTUAL_CheckFlags( (UINT32)ptr, size,
VPROT_WRITE | VPROT_COMMITTED );
}
/***********************************************************************
* IsBadHugeReadPtr32 (KERNEL32.352)
* RETURNS
* FALSE: Process has read access to entire block
* TRUE: Otherwise
*/
BOOL32 WINAPI IsBadHugeReadPtr32(
LPCVOID ptr, /* [in] Address of memory block */
UINT32 size /* [in] Size of block */
) {
return IsBadReadPtr32( ptr, size );
}
/***********************************************************************
* IsBadHugeWritePtr32 (KERNEL32.353)
* RETURNS
* FALSE: Process has write access to entire block
* TRUE: Otherwise
*/
BOOL32 WINAPI IsBadHugeWritePtr32(
LPVOID ptr, /* [in] Address of memory block */
UINT32 size /* [in] Size of block */
) {
return IsBadWritePtr32( ptr, size );
}
/***********************************************************************
* IsBadCodePtr32 (KERNEL32.351)
*
* RETURNS
* FALSE: Process has read access to specified memory
* TRUE: Otherwise
*/
BOOL32 WINAPI IsBadCodePtr32(
FARPROC32 ptr /* [in] Address of function */
) {
return !VIRTUAL_CheckFlags( (UINT32)ptr, 1, VPROT_EXEC | VPROT_COMMITTED );
}
/***********************************************************************
* IsBadStringPtr32A (KERNEL32.355)
*
* RETURNS
* FALSE: Read access to all bytes in string
* TRUE: Else
*/
BOOL32 WINAPI IsBadStringPtr32A(
LPCSTR str, /* [in] Address of string */
UINT32 max /* [in] Maximum size of string */
) {
FILE_VIEW *view;
UINT32 page, count;
if (!max) return FALSE;
if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
page = ((UINT32)str - view->base) >> page_shift;
count = page_mask + 1 - ((UINT32)str & page_mask);
while (max)
{
if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) !=
(VPROT_READ | VPROT_COMMITTED))
return TRUE;
if (count > max) count = max;
max -= count;
while (count--) if (!*str++) return FALSE;
if (++page >= view->size >> page_shift) return TRUE;
count = page_mask + 1;
}
return FALSE;
}
/***********************************************************************
* IsBadStringPtr32W (KERNEL32.356)
* See IsBadStringPtr32A
*/
BOOL32 WINAPI IsBadStringPtr32W( LPCWSTR str, UINT32 max )
{
FILE_VIEW *view;
UINT32 page, count;
if (!max) return FALSE;
if (!(view = VIRTUAL_FindView( (UINT32)str ))) return TRUE;
page = ((UINT32)str - view->base) >> page_shift;
count = (page_mask + 1 - ((UINT32)str & page_mask)) / sizeof(WCHAR);
while (max)
{
if ((view->prot[page] & (VPROT_READ | VPROT_COMMITTED)) !=
(VPROT_READ | VPROT_COMMITTED))
return TRUE;
if (count > max) count = max;
max -= count;
while (count--) if (!*str++) return FALSE;
if (++page >= view->size >> page_shift) return TRUE;
count = (page_mask + 1) / sizeof(WCHAR);
}
return FALSE;
}
/***********************************************************************
* CreateFileMapping32A (KERNEL32.46)
* Creates a named or unnamed file-mapping object for the specified file
*
* RETURNS
* Handle: Success
* 0: Mapping object does not exist
* NULL: Failure
*/
HANDLE32 WINAPI CreateFileMapping32A(
HFILE32 hFile, /* [in] Handle of file to map */
SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
DWORD protect, /* [in] Protection for mapping object */
DWORD size_high, /* [in] High-order 32 bits of object size */
DWORD size_low, /* [in] Low-order 32 bits of object size */
LPCSTR name /* [in] Name of file-mapping object */ )
{
FILE_MAPPING *mapping = NULL;
HANDLE32 handle;
BYTE vprot;
BOOL32 inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
/* First search for an object with the same name */
K32OBJ *obj = K32OBJ_FindName( name );
if (obj)
{
if (obj->type == K32OBJ_MEM_MAPPED_FILE)
{
SetLastError( ERROR_ALREADY_EXISTS );
handle = HANDLE_Alloc( PROCESS_Current(), obj,
FILE_MAP_ALL_ACCESS /*FIXME*/, inherit );
}
else
{
SetLastError( ERROR_DUP_NAME );
handle = 0;
}
K32OBJ_DecCount( obj );
return handle;
}
/* Check parameters */
TRACE(virtual,"(%x,%p,%08lx,%08lx%08lx,%s)\n",
hFile, sa, protect, size_high, size_low, name );
vprot = VIRTUAL_GetProt( protect );
if (protect & SEC_RESERVE)
{
if (hFile != INVALID_HANDLE_VALUE32)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
}
else vprot |= VPROT_COMMITTED;
if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
/* Compute the size and extend the file if necessary */
if (hFile == INVALID_HANDLE_VALUE32)
{
if (!size_high && !size_low)
{
SetLastError( ERROR_INVALID_PARAMETER );
return 0;
}
obj = NULL;
}
else /* We have a file */
{
BY_HANDLE_FILE_INFORMATION info;
DWORD access = GENERIC_READ;
if (((protect & 0xff) == PAGE_READWRITE) ||
((protect & 0xff) == PAGE_WRITECOPY) ||
((protect & 0xff) == PAGE_EXECUTE_READWRITE) ||
((protect & 0xff) == PAGE_EXECUTE_WRITECOPY))
access |= GENERIC_WRITE;
if (!(obj = HANDLE_GetObjPtr( PROCESS_Current(), hFile,
K32OBJ_FILE, access )))
goto error;
if (!GetFileInformationByHandle( hFile, &info )) goto error;
if (!size_high && !size_low)
{
size_high = info.nFileSizeHigh;
size_low = info.nFileSizeLow;
}
else if ((size_high > info.nFileSizeHigh) ||
((size_high == info.nFileSizeHigh) &&
(size_low > info.nFileSizeLow)))
{
/* We have to grow the file */
if (SetFilePointer( hFile, size_low, &size_high,
FILE_BEGIN ) == 0xffffffff) goto error;
if (!SetEndOfFile( hFile )) goto error;
}
}
/* Allocate the mapping object */
if (!(mapping = HeapAlloc( SystemHeap, 0, sizeof(*mapping) ))) goto error;
mapping->header.type = K32OBJ_MEM_MAPPED_FILE;
mapping->header.refcount = 1;
mapping->protect = vprot;
mapping->size_high = size_high;
mapping->size_low = ROUND_SIZE( 0, size_low );
mapping->file = (FILE_OBJECT *)obj;
if (!K32OBJ_AddName( &mapping->header, name )) handle = 0;
else handle = HANDLE_Alloc( PROCESS_Current(), &mapping->header,
FILE_MAP_ALL_ACCESS /*FIXME*/, inherit );
K32OBJ_DecCount( &mapping->header );
return handle;
error:
if (obj) K32OBJ_DecCount( obj );
if (mapping) HeapFree( SystemHeap, 0, mapping );
return 0;
}
/***********************************************************************
* CreateFileMapping32W (KERNEL32.47)
* See CreateFileMapping32A
*/
HANDLE32 WINAPI CreateFileMapping32W( HFILE32 hFile, LPSECURITY_ATTRIBUTES attr,
DWORD protect, DWORD size_high,
DWORD size_low, LPCWSTR name )
{
LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
HANDLE32 ret = CreateFileMapping32A( hFile, attr, protect,
size_high, size_low, nameA );
HeapFree( GetProcessHeap(), 0, nameA );
return ret;
}
/***********************************************************************
* OpenFileMapping32A (KERNEL32.397)
* Opens a named file-mapping object.
*
* RETURNS
* Handle: Success
* NULL: Failure
*/
HANDLE32 WINAPI OpenFileMapping32A(
DWORD access, /* [in] Access mode */
BOOL32 inherit, /* [in] Inherit flag */
LPCSTR name /* [in] Name of file-mapping object */
) {
HANDLE32 handle = 0;
K32OBJ *obj;
SYSTEM_LOCK();
if ((obj = K32OBJ_FindNameType( name, K32OBJ_MEM_MAPPED_FILE )))
{
handle = HANDLE_Alloc( PROCESS_Current(), obj, access, inherit );
K32OBJ_DecCount( obj );
}
SYSTEM_UNLOCK();
return handle;
}
/***********************************************************************
* OpenFileMapping32W (KERNEL32.398)
* See OpenFileMapping32A
*/
HANDLE32 WINAPI OpenFileMapping32W( DWORD access, BOOL32 inherit, LPCWSTR name)
{
LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
HANDLE32 ret = OpenFileMapping32A( access, inherit, nameA );
HeapFree( GetProcessHeap(), 0, nameA );
return ret;
}
/***********************************************************************
* VIRTUAL_DestroyMapping
*
* Destroy a FILE_MAPPING object.
*/
static void VIRTUAL_DestroyMapping( K32OBJ *ptr )
{
FILE_MAPPING *mapping = (FILE_MAPPING *)ptr;
assert( ptr->type == K32OBJ_MEM_MAPPED_FILE );
if (mapping->file) K32OBJ_DecCount( &mapping->file->header );
ptr->type = K32OBJ_UNKNOWN;
HeapFree( SystemHeap, 0, mapping );
}
/***********************************************************************
* MapViewOfFile (KERNEL32.385)
* Maps a view of a file into the address space
*
* RETURNS
* Starting address of mapped view
* NULL: Failure
*/
LPVOID WINAPI MapViewOfFile(
HANDLE32 mapping, /* [in] File-mapping object to map */
DWORD access, /* [in] Access mode */
DWORD offset_high, /* [in] High-order 32 bits of file offset */
DWORD offset_low, /* [in] Low-order 32 bits of file offset */
DWORD count /* [in] Number of bytes to map */
) {
return MapViewOfFileEx( mapping, access, offset_high,
offset_low, count, NULL );
}
/***********************************************************************
* MapViewOfFileEx (KERNEL32.386)
* Maps a view of a file into the address space
*
* RETURNS
* Starting address of mapped view
* NULL: Failure
*/
LPVOID WINAPI MapViewOfFileEx(
HANDLE32 handle, /* [in] File-mapping object to map */
DWORD access, /* [in] Access mode */
DWORD offset_high, /* [in] High-order 32 bits of file offset */
DWORD offset_low, /* [in] Low-order 32 bits of file offset */
DWORD count, /* [in] Number of bytes to map */
LPVOID addr /* [in] Suggested starting address for mapped view */
) {
FILE_MAPPING *mapping;
FILE_VIEW *view;
UINT32 ptr = (UINT32)-1, size = 0;
int flags = MAP_PRIVATE;
/* Check parameters */
if ((offset_low & granularity_mask) ||
(addr && ((UINT32)addr & granularity_mask)))
{
SetLastError( ERROR_INVALID_PARAMETER );
return NULL;
}
if (!(mapping = (FILE_MAPPING *)HANDLE_GetObjPtr( PROCESS_Current(),
handle,
K32OBJ_MEM_MAPPED_FILE,
0 /* FIXME */ )))
return NULL;
if (mapping->size_high || offset_high)
ERR(virtual, "Offsets larger than 4Gb not supported\n");
if ((offset_low >= mapping->size_low) ||
(count > mapping->size_low - offset_low))
{
SetLastError( ERROR_INVALID_PARAMETER );
goto error;
}
if (count) size = ROUND_SIZE( offset_low, count );
else size = mapping->size_low - offset_low;
switch(access)
{
case FILE_MAP_ALL_ACCESS:
case FILE_MAP_WRITE:
case FILE_MAP_WRITE | FILE_MAP_READ:
if (!(mapping->protect & VPROT_WRITE))
{
SetLastError( ERROR_INVALID_PARAMETER );
goto error;
}
flags = MAP_SHARED;
/* fall through */
case FILE_MAP_READ:
case FILE_MAP_COPY:
case FILE_MAP_COPY | FILE_MAP_READ:
if (mapping->protect & VPROT_READ) break;
/* fall through */
default:
SetLastError( ERROR_INVALID_PARAMETER );
goto error;
}
/* Map the file */
TRACE(virtual, "handle=%x size=%x offset=%lx\n",
handle, size, offset_low );
ptr = (UINT32)FILE_dommap( mapping->file, addr, 0, size, 0, offset_low,
VIRTUAL_GetUnixProt( mapping->protect ),
flags );
if (ptr == (UINT32)-1)
{
SetLastError( ERROR_OUTOFMEMORY );
goto error;
}
if (!(view = VIRTUAL_CreateView( ptr, size, offset_low, 0,
mapping->protect, mapping )))
{
SetLastError( ERROR_OUTOFMEMORY );
goto error;
}
return (LPVOID)ptr;
error:
if (ptr != (UINT32)-1) FILE_munmap( (void *)ptr, 0, size );
K32OBJ_DecCount( &mapping->header );
return NULL;
}
/***********************************************************************
* FlushViewOfFile (KERNEL32.262)
* Writes to the disk a byte range within a mapped view of a file
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL32 WINAPI FlushViewOfFile(
LPCVOID base, /* [in] Start address of byte range to flush */
DWORD cbFlush /* [in] Number of bytes in range */
) {
FILE_VIEW *view;
UINT32 addr = ROUND_ADDR( base );
TRACE(virtual, "FlushViewOfFile at %p for %ld bytes\n",
base, cbFlush );
if (!(view = VIRTUAL_FindView( addr )))
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if (!cbFlush) cbFlush = view->size;
if (!msync( (void *)addr, cbFlush, MS_SYNC )) return TRUE;
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
/***********************************************************************
* UnmapViewOfFile (KERNEL32.540)
* Unmaps a mapped view of a file.
*
* NOTES
* Should addr be an LPCVOID?
*
* RETURNS
* TRUE: Success
* FALSE: Failure
*/
BOOL32 WINAPI UnmapViewOfFile(
LPVOID addr /* [in] Address where mapped view begins */
) {
FILE_VIEW *view;
UINT32 base = ROUND_ADDR( addr );
if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
{
SetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
VIRTUAL_DeleteView( view );
return TRUE;
}