Implemented the ntdll virtual memory functions, and made the kernel
functions use them.
diff --git a/dlls/kernel/kernel32.spec b/dlls/kernel/kernel32.spec
index c688d8e..a556b9a 100644
--- a/dlls/kernel/kernel32.spec
+++ b/dlls/kernel/kernel32.spec
@@ -940,7 +940,7 @@
@ stdcall SwitchToThread() SwitchToThread
@ forward TryEnterCriticalSection ntdll.RtlTryEnterCriticalSection
@ stdcall VirtualAllocEx(long ptr long long long) VirtualAllocEx
-@ stub VirtualFreeEx
+@ stdcall VirtualFreeEx(long ptr long long) VirtualFreeEx
@ stub WriteFileGather
#Win98 and higher
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index e32a216..b52124e 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -111,6 +111,7 @@
signal_powerpc.c \
signal_sparc.c \
sync.c \
+ virtual.c \
time.c \
wcstring.c
diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c
index 321bbe8..7367503 100644
--- a/dlls/ntdll/heap.c
+++ b/dlls/ntdll/heap.c
@@ -293,17 +293,16 @@
size = (size + COMMIT_MASK) & ~COMMIT_MASK;
if (size > subheap->size) size = subheap->size;
if (size <= subheap->commitSize) return TRUE;
- if (!VirtualAlloc( (char *)subheap + subheap->commitSize,
- size - subheap->commitSize, MEM_COMMIT,
- PAGE_EXECUTE_READWRITE))
+ size -= subheap->commitSize;
+ if (NtAllocateVirtualMemory( GetCurrentProcess(), &ptr, (char *)subheap + subheap->commitSize,
+ &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
{
WARN("Could not commit %08lx bytes at %08lx for heap %08lx\n",
- size - subheap->commitSize,
- (DWORD)((char *)subheap + subheap->commitSize),
+ size, (DWORD)((char *)subheap + subheap->commitSize),
(DWORD)subheap->heap );
return FALSE;
}
- subheap->commitSize = size;
+ subheap->commitSize += size;
return TRUE;
}
@@ -315,20 +314,23 @@
*/
static inline BOOL HEAP_Decommit( SUBHEAP *subheap, void *ptr )
{
+ void *addr;
+ ULONG decommit_size;
+
DWORD size = (DWORD)((char *)ptr - (char *)subheap);
/* round to next block and add one full block */
size = ((size + COMMIT_MASK) & ~COMMIT_MASK) + COMMIT_MASK + 1;
if (size >= subheap->commitSize) return TRUE;
- if (!VirtualFree( (char *)subheap + size,
- subheap->commitSize - size, MEM_DECOMMIT ))
+ decommit_size = subheap->commitSize - size;
+ addr = (char *)subheap + size;
+
+ if (NtFreeVirtualMemory( GetCurrentProcess(), &addr, &decommit_size, MEM_DECOMMIT ))
{
- WARN("Could not decommit %08lx bytes at %08lx for heap %08lx\n",
- subheap->commitSize - size,
- (DWORD)((char *)subheap + size),
- (DWORD)subheap->heap );
+ WARN("Could not decommit %08lx bytes at %08lx for heap %p\n",
+ decommit_size, (DWORD)((char *)subheap + size), subheap->heap );
return FALSE;
}
- subheap->commitSize = size;
+ subheap->commitSize -= decommit_size;
return TRUE;
}
@@ -472,7 +474,7 @@
static BOOL HEAP_InitSubHeap( HEAP *heap, LPVOID address, DWORD flags,
DWORD commitSize, DWORD totalSize )
{
- SUBHEAP *subheap = (SUBHEAP *)address;
+ SUBHEAP *subheap;
FREE_LIST_ENTRY *pEntry;
int i;
@@ -480,15 +482,16 @@
if (flags & HEAP_SHARED)
commitSize = totalSize; /* always commit everything in a shared heap */
- if (!VirtualAlloc(address, commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
+ if (NtAllocateVirtualMemory( GetCurrentProcess(), &address, address,
+ &commitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
{
- WARN("Could not commit %08lx bytes for sub-heap %08lx\n",
- commitSize, (DWORD)address );
+ WARN("Could not commit %08lx bytes for sub-heap %p\n", commitSize, address );
return FALSE;
}
/* Fill the sub-heap structure */
+ subheap = (SUBHEAP *)address;
subheap->heap = heap;
subheap->size = totalSize;
subheap->commitSize = commitSize;
@@ -560,10 +563,10 @@
if (!address)
{
/* allocate the memory block */
- if (!(address = VirtualAlloc( NULL, totalSize, MEM_RESERVE, PAGE_EXECUTE_READWRITE )))
+ if (NtAllocateVirtualMemory( GetCurrentProcess(), &address, NULL, &totalSize,
+ MEM_RESERVE, PAGE_EXECUTE_READWRITE ))
{
- WARN("Could not VirtualAlloc %08lx bytes\n",
- totalSize );
+ WARN("Could not allocate %08lx bytes\n", totalSize );
return NULL;
}
}
@@ -573,7 +576,8 @@
if (!HEAP_InitSubHeap( heap ? heap : (HEAP *)address,
address, flags, commitSize, totalSize ))
{
- if (!base) VirtualFree( address, 0, MEM_RELEASE );
+ ULONG size = 0;
+ if (!base) NtFreeVirtualMemory( GetCurrentProcess(), &address, &size, MEM_RELEASE );
return NULL;
}
@@ -988,7 +992,9 @@
while (subheap)
{
SUBHEAP *next = subheap->next;
- VirtualFree( subheap, 0, MEM_RELEASE );
+ ULONG size = 0;
+ void *addr = subheap;
+ NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE );
subheap = next;
}
return 0;
diff --git a/dlls/ntdll/nt.c b/dlls/ntdll/nt.c
index aec0229..f000929 100644
--- a/dlls/ntdll/nt.c
+++ b/dlls/ntdll/nt.c
@@ -418,41 +418,6 @@
*/
/******************************************************************************
- * NtCreateSection [NTDLL.@]
- * ZwCreateSection [NTDLL.@]
- */
-NTSTATUS WINAPI NtCreateSection(
- OUT PHANDLE SectionHandle,
- IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
- IN PLARGE_INTEGER MaximumSize OPTIONAL,
- IN ULONG SectionPageProtection OPTIONAL,
- IN ULONG AllocationAttributes,
- IN HANDLE FileHandle OPTIONAL)
-{
- FIXME("(%p,0x%08lx,%p,%p,0x%08lx,0x%08lx,0x%08x) stub\n",
- SectionHandle,DesiredAccess, ObjectAttributes,
- MaximumSize,SectionPageProtection,AllocationAttributes,FileHandle);
- dump_ObjectAttributes(ObjectAttributes);
- return 0;
-}
-
-/******************************************************************************
- * NtOpenSection [NTDLL.@]
- * ZwOpenSection [NTDLL.@]
- */
-NTSTATUS WINAPI NtOpenSection(
- PHANDLE SectionHandle,
- ACCESS_MASK DesiredAccess,
- POBJECT_ATTRIBUTES ObjectAttributes)
-{
- FIXME("(%p,0x%08lx,%p),stub!\n",
- SectionHandle,DesiredAccess,ObjectAttributes);
- dump_ObjectAttributes(ObjectAttributes);
- return 0;
-}
-
-/******************************************************************************
* NtQuerySection [NTDLL.@]
*/
NTSTATUS WINAPI NtQuerySection(
@@ -467,44 +432,6 @@
return 0;
}
-/******************************************************************************
- * NtMapViewOfSection [NTDLL.@]
- * ZwMapViewOfSection [NTDLL.@]
- * FUNCTION: Maps a view of a section into the virtual address space of a process
- *
- * ARGUMENTS:
- * SectionHandle Handle of the section
- * ProcessHandle Handle of the process
- * BaseAddress Desired base address (or NULL) on entry
- * Actual base address of the view on exit
- * ZeroBits Number of high order address bits that must be zero
- * CommitSize Size in bytes of the initially committed section of the view
- * SectionOffset Offset in bytes from the beginning of the section to the beginning of the view
- * ViewSize Desired length of map (or zero to map all) on entry
- Actual length mapped on exit
- * InheritDisposition Specified how the view is to be shared with
- * child processes
- * AllocateType Type of allocation for the pages
- * Protect Protection for the committed region of the view
- */
-NTSTATUS WINAPI NtMapViewOfSection(
- HANDLE SectionHandle,
- HANDLE ProcessHandle,
- PVOID* BaseAddress,
- ULONG ZeroBits,
- ULONG CommitSize,
- PLARGE_INTEGER SectionOffset,
- PULONG ViewSize,
- SECTION_INHERIT InheritDisposition,
- ULONG AllocationType,
- ULONG Protect)
-{
- FIXME("(0x%08x,0x%08x,%p,0x%08lx,0x%08lx,%p,%p,0x%08x,0x%08lx,0x%08lx) stub\n",
- SectionHandle,ProcessHandle,BaseAddress,ZeroBits,CommitSize,SectionOffset,
- ViewSize,InheritDisposition,AllocationType,Protect);
- return 0;
-}
-
/*
* ports
*/
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index fdc0ffa..75df84c 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -63,7 +63,7 @@
@ stub NtAlertThread
@ stdcall NtAllocateLocallyUniqueId(ptr) NtAllocateLocallyUniqueId
@ stdcall NtAllocateUuids(ptr ptr ptr) NtAllocateUuids
-@ stub NtAllocateVirtualMemory
+@ stdcall NtAllocateVirtualMemory(long ptr ptr ptr long long) NtAllocateVirtualMemory
@ stub NtCallbackReturn
@ stub NtCancelIoFile
@ stub NtCancelTimer
@@ -86,7 +86,7 @@
@ stdcall NtCreatePort(long long long long long) NtCreatePort
@ stub NtCreateProcess
@ stub NtCreateProfile
-@ stdcall NtCreateSection(long long long long long long long) NtCreateSection
+@ stdcall NtCreateSection(ptr long ptr ptr long long long) NtCreateSection
@ stdcall NtCreateSemaphore(ptr long ptr long long) NtCreateSemaphore
@ stdcall NtCreateSymbolicLinkObject(ptr long ptr ptr) NtCreateSymbolicLinkObject
@ stub NtCreateThread
@@ -108,9 +108,9 @@
@ stub NtFlushBuffersFile
@ stub NtFlushInstructionCache
@ stdcall NtFlushKey(long) NtFlushKey
-@ stub NtFlushVirtualMemory
+@ stdcall NtFlushVirtualMemory(long ptr ptr long) NtFlushVirtualMemory
@ stub NtFlushWriteBuffer
-@ stub NtFreeVirtualMemory
+@ stdcall NtFreeVirtualMemory(long ptr ptr long) NtFreeVirtualMemory
@ stdcall NtFsControlFile(long long long long long long long long long long) NtFsControlFile
@ stub NtGetContextThread
@ stub NtGetPlugPlayEvent
@@ -122,9 +122,9 @@
@ stub NtLoadDriver
@ stdcall NtLoadKey(ptr ptr) NtLoadKey
@ stub NtLockFile
-@ stub NtLockVirtualMemory
+@ stdcall NtLockVirtualMemory(long ptr ptr long) NtLockVirtualMemory
@ stub NtMakeTemporaryObject
-@ stdcall NtMapViewOfSection(long long long long long long long long long long) NtMapViewOfSection
+@ stdcall NtMapViewOfSection(long long ptr long long ptr ptr long long long) NtMapViewOfSection
@ stub NtNotifyChangeDirectoryFile
@ stdcall NtNotifyChangeKey(long long ptr ptr ptr long long ptr long long) NtNotifyChangeKey
@ stdcall NtOpenDirectoryObject(long long long) NtOpenDirectoryObject
@@ -137,7 +137,7 @@
@ stub NtOpenObjectAuditAlarm
@ stub NtOpenProcess
@ stdcall NtOpenProcessToken(long long long) NtOpenProcessToken
-@ stdcall NtOpenSection(long long long) NtOpenSection
+@ stdcall NtOpenSection(ptr long ptr) NtOpenSection
@ stdcall NtOpenSemaphore(long long ptr) NtOpenSemaphore
@ stdcall NtOpenSymbolicLinkObject (long long long) NtOpenSymbolicLinkObject
@ stub NtOpenThread
@@ -147,7 +147,7 @@
@ stub NtPrivilegeCheck
@ stub NtPrivilegeObjectAuditAlarm
@ stub NtPrivilegedServiceAuditAlarm
-@ stub NtProtectVirtualMemory
+@ stdcall NtProtectVirtualMemory(long ptr ptr long ptr) NtProtectVirtualMemory
@ stdcall NtPulseEvent(long ptr) NtPulseEvent
@ stub NtQueryAttributesFile
@ stub NtQueryDefaultLocale
@@ -176,7 +176,7 @@
@ stub NtQueryTimer
@ stdcall NtQueryTimerResolution(long long long) NtQueryTimerResolution
@ stdcall NtQueryValueKey(long long long long long long) NtQueryValueKey
-@ stub NtQueryVirtualMemory
+@ stdcall NtQueryVirtualMemory(long ptr long ptr long ptr) NtQueryVirtualMemory
@ stdcall NtQueryVolumeInformationFile(long ptr ptr long long) NtQueryVolumeInformationFile
@ stdcall NtRaiseException(ptr ptr long) NtRaiseException
@ stub NtRaiseHardError
@@ -241,8 +241,8 @@
@ stub NtUnloadDriver
@ stdcall NtUnloadKey(long) NtUnloadKey
@ stub NtUnlockFile
-@ stub NtUnlockVirtualMemory
-@ stub NtUnmapViewOfSection
+@ stdcall NtUnlockVirtualMemory(long ptr ptr long) NtUnlockVirtualMemory
+@ stdcall NtUnmapViewOfSection(long ptr) NtUnmapViewOfSection
@ stub NtVdmControl
@ stub NtW32Call
@ stub NtWaitForMultipleObjects
@@ -581,7 +581,7 @@
@ stub ZwAlertThread
@ stub ZwAllocateLocallyUniqueId
@ stub ZwAllocateUuids
-@ stub ZwAllocateVirtualMemory
+@ stdcall ZwAllocateVirtualMemory(long ptr ptr ptr long long) NtAllocateVirtualMemory
@ stub ZwCallbackReturn
@ stub ZwCancelIoFile
@ stub ZwCancelTimer
@@ -604,7 +604,7 @@
@ stdcall ZwCreatePort(long long long long long) NtCreatePort
@ stub ZwCreateProcess
@ stub ZwCreateProfile
-@ stdcall ZwCreateSection(long long long long long long long) NtCreateSection
+@ stdcall ZwCreateSection(ptr long ptr ptr long long long) NtCreateSection
@ stub ZwCreateSemaphore
@ stub ZwCreateSymbolicLinkObject
@ stub ZwCreateThread
@@ -625,9 +625,9 @@
@ stub ZwFlushBuffersFile
@ stub ZwFlushInstructionCache
@ stdcall ZwFlushKey(long) NtFlushKey
-@ stub ZwFlushVirtualMemory
+@ stdcall ZwFlushVirtualMemory(long ptr ptr long) NtFlushVirtualMemory
@ stub ZwFlushWriteBuffer
-@ stub ZwFreeVirtualMemory
+@ stdcall ZwFreeVirtualMemory(long ptr ptr long) NtFreeVirtualMemory
@ stdcall ZwFsControlFile(long long long long long long long long long long) NtFsControlFile
@ stub ZwGetContextThread
@ stub ZwGetPlugPlayEvent
@@ -639,9 +639,9 @@
@ stub ZwLoadDriver
@ stdcall ZwLoadKey(ptr ptr) NtLoadKey
@ stub ZwLockFile
-@ stub ZwLockVirtualMemory
+@ stdcall ZwLockVirtualMemory(long ptr ptr long) NtLockVirtualMemory
@ stub ZwMakeTemporaryObject
-@ stdcall ZwMapViewOfSection(long long long long long long long long long long) NtMapViewOfSection
+@ stdcall ZwMapViewOfSection(long long ptr long long ptr ptr long long long) NtMapViewOfSection
@ stub ZwNotifyChangeDirectoryFile
@ stdcall ZwNotifyChangeKey(long long ptr ptr ptr long long ptr long long) NtNotifyChangeKey
@ stdcall ZwOpenDirectoryObject(long long long) NtOpenDirectoryObject
@@ -654,7 +654,7 @@
@ stub ZwOpenObjectAuditAlarm
@ stub ZwOpenProcess
@ stdcall ZwOpenProcessToken(long long long) NtOpenProcessToken
-@ stdcall ZwOpenSection(long long long) NtOpenSection
+@ stdcall ZwOpenSection(ptr long ptr) NtOpenSection
@ stub ZwOpenSemaphore
@ stub ZwOpenSymbolicLinkObject
@ stub ZwOpenThread
@@ -664,7 +664,7 @@
@ stub ZwPrivilegeCheck
@ stub ZwPrivilegeObjectAuditAlarm
@ stub ZwPrivilegedServiceAuditAlarm
-@ stub ZwProtectVirtualMemory
+@ stdcall ZwProtectVirtualMemory(long ptr ptr long ptr) NtProtectVirtualMemory
@ stub ZwPulseEvent
@ stub ZwQueryAttributesFile
@ stub ZwQueryDefaultLocale
@@ -693,7 +693,7 @@
@ stub ZwQueryTimer
@ stub ZwQueryTimerResolution
@ stdcall ZwQueryValueKey(long ptr long ptr long ptr) NtQueryValueKey
-@ stub ZwQueryVirtualMemory
+@ stdcall ZwQueryVirtualMemory(long ptr long ptr long ptr) NtQueryVirtualMemory
@ stdcall ZwQueryVolumeInformationFile(long ptr ptr long long) NtQueryVolumeInformationFile
@ stub ZwRaiseException
@ stub ZwRaiseHardError
@@ -756,8 +756,8 @@
@ stub ZwUnloadDriver
@ stdcall ZwUnloadKey(long) NtUnloadKey
@ stub ZwUnlockFile
-@ stub ZwUnlockVirtualMemory
-@ stub ZwUnmapViewOfSection
+@ stdcall ZwUnlockVirtualMemory(long ptr ptr long) NtUnlockVirtualMemory
+@ stdcall ZwUnmapViewOfSection(long ptr) NtUnmapViewOfSection
@ stub ZwVdmControl
@ stub ZwW32Call
@ stub ZwWaitForMultipleObjects
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
new file mode 100644
index 0000000..15fd396
--- /dev/null
+++ b/dlls/ntdll/virtual.c
@@ -0,0 +1,1535 @@
+/*
+ * Win32 virtual memory functions
+ *
+ * Copyright 1997, 2002 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <assert.h>
+#include <errno.h>
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+
+#include "winternl.h"
+#include "global.h"
+#include "wine/library.h"
+#include "wine/server.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(virtual);
+WINE_DECLARE_DEBUG_CHANNEL(module);
+
+#ifndef MS_SYNC
+#define MS_SYNC 0
+#endif
+
+/* File view */
+typedef struct _FV
+{
+ struct _FV *next; /* Next view */
+ struct _FV *prev; /* Prev view */
+ void *base; /* Base address */
+ UINT size; /* Size in bytes */
+ UINT flags; /* Allocation flags */
+ HANDLE mapping; /* Handle to the 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-view flags */
+#define VFLAG_SYSTEM 0x01
+#define VFLAG_VALLOC 0x02 /* allocated by VirtualAlloc */
+
+/* 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;
+static CRITICAL_SECTION csVirtual = CRITICAL_SECTION_INIT("csVirtual");
+
+#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 page_size 0x1000
+#else
+static UINT page_shift;
+static UINT page_mask;
+static UINT page_size;
+#endif /* __i386__ */
+#define granularity_mask 0xffff /* Allocation granularity (usually 64k) */
+
+#define ADDRESS_SPACE_LIMIT ((void *)0xc0000000) /* top of the user address space */
+
+#define ROUND_ADDR(addr,mask) \
+ ((void *)((UINT_PTR)(addr) & ~(mask)))
+
+#define ROUND_SIZE(addr,size) \
+ (((UINT)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
+
+#define VIRTUAL_DEBUG_DUMP_VIEW(view) \
+ if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
+
+static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, DWORD offset_low,
+ DWORD offset_high, int prot, int flags, BOOL *removable );
+
+
+/***********************************************************************
+ * 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 )
+{
+ UINT i, count;
+ char *addr = view->base;
+ BYTE prot = view->prot[0];
+
+ DPRINTF( "View: %p - %p", addr, addr + view->size - 1 );
+ if (view->flags & VFLAG_SYSTEM)
+ DPRINTF( " (system)\n" );
+ else if (view->flags & VFLAG_VALLOC)
+ DPRINTF( " (valloc)\n" );
+ else if (view->mapping)
+ DPRINTF( " %d\n", view->mapping );
+ else
+ DPRINTF( " (anonymous)\n");
+
+ for (count = i = 1; i < view->size >> page_shift; i++, count++)
+ {
+ if (view->prot[i] == prot) continue;
+ DPRINTF( " %p - %p %s\n",
+ addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) );
+ addr += (count << page_shift);
+ prot = view->prot[i];
+ count = 0;
+ }
+ if (count)
+ DPRINTF( " %p - %p %s\n",
+ addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) );
+}
+
+
+/***********************************************************************
+ * VIRTUAL_Dump
+ */
+void VIRTUAL_Dump(void)
+{
+ FILE_VIEW *view;
+ DPRINTF( "\nDump of all virtual memory views:\n\n" );
+ RtlEnterCriticalSection(&csVirtual);
+ view = VIRTUAL_FirstView;
+ while (view)
+ {
+ VIRTUAL_DumpView( view );
+ view = view->next;
+ }
+ RtlLeaveCriticalSection(&csVirtual);
+}
+
+
+/***********************************************************************
+ * VIRTUAL_FindView
+ *
+ * Find the view containing a given address.
+ *
+ * RETURNS
+ * View: Success
+ * NULL: Failure
+ */
+static FILE_VIEW *VIRTUAL_FindView( const void *addr ) /* [in] Address */
+{
+ FILE_VIEW *view;
+
+ RtlEnterCriticalSection(&csVirtual);
+ view = VIRTUAL_FirstView;
+ while (view)
+ {
+ if (view->base > addr)
+ {
+ view = NULL;
+ break;
+ }
+ if ((char*)view->base + view->size > (char*)addr) break;
+ view = view->next;
+ }
+ RtlLeaveCriticalSection(&csVirtual);
+ return view;
+}
+
+
+/***********************************************************************
+ * VIRTUAL_CreateView
+ *
+ * Create a new view and add it in the linked list.
+ */
+static FILE_VIEW *VIRTUAL_CreateView( void *base, UINT size, UINT flags,
+ BYTE vprot, HANDLE mapping )
+{
+ FILE_VIEW *view, *prev;
+
+ /* Create the view structure */
+
+ assert( !((unsigned int)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->mapping = mapping;
+ view->protect = vprot;
+ view->handlerProc = NULL;
+ memset( view->prot, vprot, size );
+
+ /* Duplicate the mapping handle */
+
+ if (view->mapping &&
+ NtDuplicateObject( GetCurrentProcess(), view->mapping,
+ GetCurrentProcess(), &view->mapping,
+ 0, 0, DUPLICATE_SAME_ACCESS ))
+ {
+ free( view );
+ return NULL;
+ }
+
+ /* Insert it in the linked list */
+
+ RtlEnterCriticalSection(&csVirtual);
+ 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;
+ }
+ RtlLeaveCriticalSection(&csVirtual);
+ VIRTUAL_DEBUG_DUMP_VIEW( view );
+ return view;
+}
+
+
+/***********************************************************************
+ * VIRTUAL_DeleteView
+ * Deletes a view.
+ *
+ * RETURNS
+ * None
+ */
+static void VIRTUAL_DeleteView( FILE_VIEW *view ) /* [in] View */
+{
+ if (!(view->flags & VFLAG_SYSTEM))
+ munmap( (void *)view->base, view->size );
+ RtlEnterCriticalSection(&csVirtual);
+ if (view->next) view->next->prev = view->prev;
+ if (view->prev) view->prev->next = view->next;
+ else VIRTUAL_FirstView = view->next;
+ RtlLeaveCriticalSection(&csVirtual);
+ if (view->mapping) NtClose( view->mapping );
+ 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_WRITECOPY) 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 (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS;
+ }
+
+ 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:
+ /* MSDN CreateFileMapping() states that if PAGE_WRITECOPY is given,
+ * that the hFile must have been opened with GENERIC_READ and
+ * GENERIC_WRITE access. This is WRONG as tests show that you
+ * only need GENERIC_READ access (at least for Win9x,
+ * FIXME: what about NT?). Thus, we don't put VPROT_WRITE in
+ * PAGE_WRITECOPY and PAGE_EXECUTE_WRITECOPY.
+ */
+ vprot = VPROT_READ | 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;
+ break;
+ case PAGE_EXECUTE_WRITECOPY:
+ /* See comment for PAGE_WRITECOPY above */
+ vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY;
+ 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 BOOL VIRTUAL_SetProt( FILE_VIEW *view, /* [in] Pointer to view */
+ void *base, /* [in] Starting address */
+ UINT size, /* [in] Size in bytes */
+ BYTE vprot ) /* [in] Protections to use */
+{
+ TRACE("%p-%p %s\n",
+ base, (char *)base + size - 1, VIRTUAL_GetProtStr( vprot ) );
+
+ if (mprotect( base, size, VIRTUAL_GetUnixProt(vprot) ))
+ return FALSE; /* FIXME: last error */
+
+ memset( view->prot + (((char *)base - (char *)view->base) >> page_shift),
+ vprot, size >> page_shift );
+ VIRTUAL_DEBUG_DUMP_VIEW( view );
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * anon_mmap_aligned
+ *
+ * Create an anonymous mapping aligned to the allocation granularity.
+ */
+static NTSTATUS anon_mmap_aligned( void **addr, unsigned int size, int prot, int flags )
+{
+ void *ptr, *base = *addr;
+ unsigned int view_size = size + (base ? 0 : granularity_mask + 1);
+
+ if ((ptr = wine_anon_mmap( base, view_size, prot, flags )) == (void *)-1)
+ {
+ if (errno == ENOMEM) return STATUS_NO_MEMORY;
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!base)
+ {
+ /* Release the extra memory while keeping the range
+ * starting on the granularity boundary. */
+ if ((unsigned int)ptr & granularity_mask)
+ {
+ unsigned int extra = granularity_mask + 1 - ((unsigned int)ptr & granularity_mask);
+ munmap( ptr, extra );
+ ptr = (char *)ptr + extra;
+ view_size -= extra;
+ }
+ if (view_size > size)
+ munmap( (char *)ptr + size, view_size - size );
+ }
+ else if (ptr != base)
+ {
+ /* We couldn't get the address we wanted */
+ munmap( ptr, view_size );
+ return STATUS_CONFLICTING_ADDRESSES;
+ }
+ *addr = ptr;
+ return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ * do_relocations
+ *
+ * Apply the relocations to a mapped PE image
+ */
+static int do_relocations( char *base, const IMAGE_DATA_DIRECTORY *dir,
+ int delta, DWORD total_size )
+{
+ IMAGE_BASE_RELOCATION *rel;
+
+ TRACE_(module)( "relocating from %p-%p to %p-%p\n",
+ base - delta, base - delta + total_size, base, base + total_size );
+
+ for (rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress);
+ ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock;
+ rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock) )
+ {
+ char *page = base + rel->VirtualAddress;
+ WORD *TypeOffset = (WORD *)(rel + 1);
+ int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset);
+
+ if (!count) continue;
+
+ /* sanity checks */
+ if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size ||
+ page > base + total_size)
+ {
+ ERR_(module)("invalid relocation %p,%lx,%ld at %p,%lx,%lx\n",
+ rel, rel->VirtualAddress, rel->SizeOfBlock,
+ base, dir->VirtualAddress, dir->Size );
+ return 0;
+ }
+
+ TRACE_(module)("%ld relocations for page %lx\n", rel->SizeOfBlock, rel->VirtualAddress);
+
+ /* patching in reverse order */
+ for (i = 0 ; i < count; i++)
+ {
+ int offset = TypeOffset[i] & 0xFFF;
+ int type = TypeOffset[i] >> 12;
+ switch(type)
+ {
+ case IMAGE_REL_BASED_ABSOLUTE:
+ break;
+ case IMAGE_REL_BASED_HIGH:
+ *(short*)(page+offset) += HIWORD(delta);
+ break;
+ case IMAGE_REL_BASED_LOW:
+ *(short*)(page+offset) += LOWORD(delta);
+ break;
+ case IMAGE_REL_BASED_HIGHLOW:
+ *(int*)(page+offset) += delta;
+ /* FIXME: if this is an exported address, fire up enhanced logic */
+ break;
+ default:
+ FIXME_(module)("Unknown/unsupported fixup type %d.\n", type);
+ break;
+ }
+ }
+ }
+ return 1;
+}
+
+
+/***********************************************************************
+ * map_image
+ *
+ * Map an executable (PE format) image into memory.
+ */
+static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, DWORD total_size,
+ DWORD header_size, int shared_fd, DWORD shared_size,
+ BOOL removable, PVOID *addr_ptr )
+{
+ IMAGE_DOS_HEADER *dos;
+ IMAGE_NT_HEADERS *nt;
+ IMAGE_SECTION_HEADER *sec;
+ IMAGE_DATA_DIRECTORY *imports;
+ NTSTATUS status = STATUS_INVALID_IMAGE_FORMAT; /* generic error (FIXME) */
+ int i, pos;
+ FILE_VIEW *view;
+ char *ptr;
+
+ /* zero-map the whole range */
+
+ if (base < (char *)0x110000 || /* make sure the DOS area remains free */
+ (ptr = wine_anon_mmap( base, total_size,
+ PROT_READ | PROT_WRITE | PROT_EXEC, 0 )) == (char *)-1)
+ {
+ ptr = wine_anon_mmap( NULL, total_size,
+ PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
+ if (ptr == (char *)-1)
+ {
+ ERR_(module)("Not enough memory for module (%ld bytes)\n", total_size);
+ goto error;
+ }
+ }
+ TRACE_(module)( "mapped PE file at %p-%p\n", ptr, ptr + total_size );
+
+ /* map the header */
+
+ if (VIRTUAL_mmap( fd, ptr, header_size, 0, 0, PROT_READ,
+ MAP_PRIVATE | MAP_FIXED, &removable ) == (char *)-1) goto error;
+ dos = (IMAGE_DOS_HEADER *)ptr;
+ nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
+ if ((char *)(nt + 1) > ptr + header_size) goto error;
+
+ sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
+ if ((char *)(sec + nt->FileHeader.NumberOfSections) > ptr + header_size) goto error;
+
+ imports = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT;
+ if (!imports->Size || !imports->VirtualAddress) imports = NULL;
+
+ /* check the architecture */
+
+ if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
+ {
+ MESSAGE("Trying to load PE image for unsupported architecture (");
+ switch (nt->FileHeader.Machine)
+ {
+ case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break;
+ case IMAGE_FILE_MACHINE_I860: MESSAGE("I860"); break;
+ case IMAGE_FILE_MACHINE_R3000: MESSAGE("R3000"); break;
+ case IMAGE_FILE_MACHINE_R4000: MESSAGE("R4000"); break;
+ case IMAGE_FILE_MACHINE_R10000: MESSAGE("R10000"); break;
+ case IMAGE_FILE_MACHINE_ALPHA: MESSAGE("Alpha"); break;
+ case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break;
+ default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break;
+ }
+ MESSAGE(")\n");
+ goto error;
+ }
+
+ /* map all the sections */
+
+ for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
+ {
+ DWORD size;
+
+ /* a few sanity checks */
+ size = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
+ if (sec->VirtualAddress > total_size || size > total_size || size < sec->VirtualAddress)
+ {
+ ERR_(module)( "Section %.8s too large (%lx+%lx/%lx)\n",
+ sec->Name, sec->VirtualAddress, sec->Misc.VirtualSize, total_size );
+ goto error;
+ }
+
+ if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) &&
+ (sec->Characteristics & IMAGE_SCN_MEM_WRITE))
+ {
+ size = ROUND_SIZE( 0, sec->Misc.VirtualSize );
+ TRACE_(module)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n",
+ sec->Name, ptr + sec->VirtualAddress,
+ sec->PointerToRawData, pos, sec->SizeOfRawData,
+ size, sec->Characteristics );
+ if (VIRTUAL_mmap( shared_fd, ptr + sec->VirtualAddress, size,
+ pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_SHARED|MAP_FIXED, NULL ) == (void *)-1)
+ {
+ ERR_(module)( "Could not map shared section %.8s\n", sec->Name );
+ goto error;
+ }
+
+ /* check if the import directory falls inside this section */
+ if (imports && imports->VirtualAddress >= sec->VirtualAddress &&
+ imports->VirtualAddress < sec->VirtualAddress + size)
+ {
+ UINT_PTR base = imports->VirtualAddress & ~page_mask;
+ UINT_PTR end = base + ROUND_SIZE( imports->VirtualAddress, imports->Size );
+ if (end > sec->VirtualAddress + size) end = sec->VirtualAddress + size;
+ if (end > base) VIRTUAL_mmap( shared_fd, ptr + base, end - base,
+ pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_PRIVATE|MAP_FIXED, NULL );
+ }
+ pos += size;
+ continue;
+ }
+
+ TRACE_(module)( "mapping section %.8s at %p off %lx size %lx flags %lx\n",
+ sec->Name, ptr + sec->VirtualAddress,
+ sec->PointerToRawData, sec->SizeOfRawData,
+ sec->Characteristics );
+
+ if (sec->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue;
+ if (!sec->PointerToRawData || !sec->SizeOfRawData) continue;
+
+ /* Note: if the section is not aligned properly VIRTUAL_mmap will magically
+ * fall back to read(), so we don't need to check anything here.
+ */
+ if (VIRTUAL_mmap( fd, ptr + sec->VirtualAddress, sec->SizeOfRawData,
+ sec->PointerToRawData, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_PRIVATE | MAP_FIXED, &removable ) == (void *)-1)
+ {
+ ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name );
+ goto error;
+ }
+
+ if ((sec->SizeOfRawData < sec->Misc.VirtualSize) && (sec->SizeOfRawData & page_mask))
+ {
+ DWORD end = ROUND_SIZE( 0, sec->SizeOfRawData );
+ if (end > sec->Misc.VirtualSize) end = sec->Misc.VirtualSize;
+ TRACE_(module)("clearing %p - %p\n",
+ ptr + sec->VirtualAddress + sec->SizeOfRawData,
+ ptr + sec->VirtualAddress + end );
+ memset( ptr + sec->VirtualAddress + sec->SizeOfRawData, 0,
+ end - sec->SizeOfRawData );
+ }
+ }
+
+
+ /* perform base relocation, if necessary */
+
+ if (ptr != base)
+ {
+ const IMAGE_DATA_DIRECTORY *relocs;
+
+ relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ if (!relocs->VirtualAddress || !relocs->Size)
+ {
+ if (nt->OptionalHeader.ImageBase == 0x400000)
+ ERR("Standard load address for a Win32 program (0x00400000) not available - security-patched kernel ?\n");
+ else
+ ERR( "FATAL: Need to relocate module from addr %lx, but there are no relocation records\n",
+ nt->OptionalHeader.ImageBase );
+ goto error;
+ }
+
+ /* FIXME: If we need to relocate a system DLL (base > 2GB) we should
+ * really make sure that the *new* base address is also > 2GB.
+ * Some DLLs really check the MSB of the module handle :-/
+ */
+ if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((DWORD)base & 0x80000000))
+ ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" );
+
+ if (!do_relocations( ptr, relocs, ptr - base, total_size ))
+ {
+ goto error;
+ }
+ }
+
+ if (removable) hmapping = 0; /* don't keep handle open on removable media */
+ if (!(view = VIRTUAL_CreateView( ptr, total_size, 0, VPROT_COMMITTED|VPROT_READ, hmapping )))
+ {
+ status = STATUS_NO_MEMORY;
+ goto error;
+ }
+
+ /* set the image protections */
+
+ sec = (IMAGE_SECTION_HEADER*)((char *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
+ for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
+ {
+ DWORD size = ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
+ BYTE vprot = VPROT_COMMITTED;
+ if (sec->Characteristics & IMAGE_SCN_MEM_READ) vprot |= VPROT_READ;
+ if (sec->Characteristics & IMAGE_SCN_MEM_WRITE) vprot |= VPROT_WRITE|VPROT_WRITECOPY;
+ if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC;
+
+ /* make sure the import directory is writable */
+ if (imports && imports->VirtualAddress >= sec->VirtualAddress &&
+ imports->VirtualAddress < sec->VirtualAddress + size)
+ vprot |= VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY;
+
+ VIRTUAL_SetProt( view, ptr + sec->VirtualAddress, size, vprot );
+ }
+
+ close( fd );
+ *addr_ptr = ptr;
+ return STATUS_SUCCESS;
+
+ error:
+ if (ptr != (char *)-1) munmap( ptr, total_size );
+ close( fd );
+ return status;
+}
+
+
+/***********************************************************************
+ * is_current_process
+ *
+ * Check whether a process handle is for the current process.
+ */
+static BOOL is_current_process( HANDLE handle )
+{
+ BOOL ret = FALSE;
+
+ if (handle == GetCurrentProcess()) return TRUE;
+ SERVER_START_REQ( get_process_info )
+ {
+ req->handle = handle;
+ if (!wine_server_call( req ))
+ ret = ((DWORD)reply->pid == GetCurrentProcessId());
+ }
+ SERVER_END_REQ;
+ return ret;
+}
+
+
+/***********************************************************************
+ * VIRTUAL_Init
+ */
+#ifndef page_mask
+DECL_GLOBAL_CONSTRUCTOR(VIRTUAL_Init)
+{
+ page_size = getpagesize();
+ page_mask = page_size - 1;
+ /* 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 /* page_mask */
+
+
+/***********************************************************************
+ * VIRTUAL_SetFaultHandler
+ */
+BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg )
+{
+ FILE_VIEW *view;
+
+ if (!(view = VIRTUAL_FindView( addr ))) return FALSE;
+ view->handlerProc = proc;
+ view->handlerArg = arg;
+ return TRUE;
+}
+
+/***********************************************************************
+ * VIRTUAL_HandleFault
+ */
+DWORD VIRTUAL_HandleFault( LPCVOID addr )
+{
+ FILE_VIEW *view = VIRTUAL_FindView( addr );
+ DWORD ret = EXCEPTION_ACCESS_VIOLATION;
+
+ if (view)
+ {
+ if (view->handlerProc)
+ {
+ if (view->handlerProc(view->handlerArg, addr)) ret = 0; /* handled */
+ }
+ else
+ {
+ BYTE vprot = view->prot[((char *)addr - (char *)view->base) >> page_shift];
+ void *page = (void *)((UINT_PTR)addr & ~page_mask);
+ char *stack = (char *)NtCurrentTeb()->stack_base + SIGNAL_STACK_SIZE + page_mask + 1;
+ if (vprot & VPROT_GUARD)
+ {
+ VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD );
+ ret = STATUS_GUARD_PAGE_VIOLATION;
+ }
+ /* is it inside the stack guard pages? */
+ if (((char *)addr >= stack) && ((char *)addr < stack + 2*(page_mask+1)))
+ ret = STATUS_STACK_OVERFLOW;
+ }
+ }
+ return ret;
+}
+
+
+
+/***********************************************************************
+ * unaligned_mmap
+ *
+ * Linux kernels before 2.4.x can support non page-aligned offsets, as
+ * long as the offset is aligned to the filesystem block size. This is
+ * a big performance gain so we want to take advantage of it.
+ *
+ * However, when we use 64-bit file support this doesn't work because
+ * glibc rejects unaligned offsets. Also glibc 2.1.3 mmap64 is broken
+ * in that it rounds unaligned offsets down to a page boundary. For
+ * these reasons we do a direct system call here.
+ */
+static void *unaligned_mmap( void *addr, size_t length, unsigned int prot,
+ unsigned int flags, int fd, unsigned int offset_low,
+ unsigned int offset_high )
+{
+#if defined(linux) && defined(__i386__) && defined(__GNUC__)
+ if (!offset_high && (offset_low & page_mask))
+ {
+ int ret;
+
+ struct
+ {
+ void *addr;
+ unsigned int length;
+ unsigned int prot;
+ unsigned int flags;
+ unsigned int fd;
+ unsigned int offset;
+ } args;
+
+ args.addr = addr;
+ args.length = length;
+ args.prot = prot;
+ args.flags = flags;
+ args.fd = fd;
+ args.offset = offset_low;
+
+ __asm__ __volatile__("push %%ebx\n\t"
+ "movl %2,%%ebx\n\t"
+ "int $0x80\n\t"
+ "popl %%ebx"
+ : "=a" (ret)
+ : "0" (90), /* SYS_mmap */
+ "g" (&args) );
+ if (ret < 0 && ret > -4096)
+ {
+ errno = -ret;
+ ret = -1;
+ }
+ return (void *)ret;
+ }
+#endif
+ return mmap( addr, length, prot, flags, fd, ((off_t)offset_high << 32) | offset_low );
+}
+
+
+/***********************************************************************
+ * VIRTUAL_mmap
+ *
+ * Wrapper for mmap() that handles anonymous mappings portably,
+ * and falls back to read if mmap of a file fails.
+ */
+static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size,
+ DWORD offset_low, DWORD offset_high,
+ int prot, int flags, BOOL *removable )
+{
+ int pos;
+ LPVOID ret;
+ off_t offset;
+ BOOL is_shared_write = FALSE;
+
+ if (fd == -1) return wine_anon_mmap( start, size, prot, flags );
+
+ if (prot & PROT_WRITE)
+ {
+#ifdef MAP_SHARED
+ if (flags & MAP_SHARED) is_shared_write = TRUE;
+#endif
+#ifdef MAP_PRIVATE
+ if (!(flags & MAP_PRIVATE)) is_shared_write = TRUE;
+#endif
+ }
+
+ if (removable && *removable)
+ {
+ /* if on removable media, try using read instead of mmap */
+ if (!is_shared_write) goto fake_mmap;
+ *removable = FALSE;
+ }
+
+ if ((ret = unaligned_mmap( start, size, prot, flags, fd,
+ offset_low, offset_high )) != (LPVOID)-1) return ret;
+
+ /* mmap() failed; if this is because the file offset is not */
+ /* page-aligned (EINVAL), or because the underlying filesystem */
+ /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */
+
+ if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return ret;
+ if (is_shared_write) return ret; /* we cannot fake shared write mappings */
+
+ fake_mmap:
+ /* Reserve the memory with an anonymous mmap */
+ ret = wine_anon_mmap( start, size, PROT_READ | PROT_WRITE, flags );
+ if (ret == (LPVOID)-1) return ret;
+ /* Now read in the file */
+ offset = ((off_t)offset_high << 32) | offset_low;
+ if ((pos = lseek( fd, offset, SEEK_SET )) == -1)
+ {
+ munmap( ret, size );
+ return (LPVOID)-1;
+ }
+ read( fd, ret, size );
+ lseek( fd, pos, SEEK_SET ); /* Restore the file pointer */
+ mprotect( ret, size, prot ); /* Set the right protection */
+ return ret;
+}
+
+
+/***********************************************************************
+ * NtAllocateVirtualMemory (NTDLL.@)
+ * ZwAllocateVirtualMemory (NTDLL.@)
+ */
+NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, PVOID addr,
+ ULONG *size_ptr, ULONG type, ULONG protect )
+{
+ FILE_VIEW *view;
+ void *base;
+ BYTE vprot;
+ DWORD size = *size_ptr;
+
+ if (!is_current_process( process ))
+ {
+ ERR("Unsupported on other process\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ TRACE("%p %08lx %lx %08lx\n", addr, size, type, protect );
+
+ /* Round parameters to a page boundary */
+
+ if (size > 0x7fc00000) return STATUS_WORKING_SET_LIMIT_RANGE; /* 2Gb - 4Mb */
+
+ if (addr)
+ {
+ if (type & MEM_RESERVE) /* Round down to 64k boundary */
+ base = ROUND_ADDR( addr, granularity_mask );
+ else
+ base = ROUND_ADDR( addr, page_mask );
+ size = (((UINT_PTR)addr + size + page_mask) & ~page_mask) - (UINT_PTR)base;
+
+ /* disallow low 64k, wrap-around and kernel space */
+ if (((char *)base <= (char *)granularity_mask) ||
+ ((char *)base + size < (char *)base) ||
+ ((char *)base + size > (char *)ADDRESS_SPACE_LIMIT))
+ return STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ base = NULL;
+ 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("MEM_TOP_DOWN ignored\n");
+ type &= ~MEM_TOP_DOWN;
+ }
+
+ /* Compute the alloc type flags */
+
+ if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)) ||
+ (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)))
+ {
+ ERR("called with wrong alloc type flags (%08lx) !\n", type);
+ return STATUS_INVALID_PARAMETER;
+ }
+ if (type & (MEM_COMMIT | MEM_SYSTEM))
+ vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
+ else vprot = 0;
+
+ /* Reserve the memory */
+
+ if ((type & MEM_RESERVE) || !base)
+ {
+ if (type & MEM_SYSTEM)
+ {
+ if (!(view = VIRTUAL_CreateView( base, size, VFLAG_VALLOC | VFLAG_SYSTEM, vprot, 0 )))
+ return STATUS_NO_MEMORY;
+ }
+ else
+ {
+ NTSTATUS res = anon_mmap_aligned( &base, size, VIRTUAL_GetUnixProt( vprot ), 0 );
+ if (res) return res;
+
+ if (!(view = VIRTUAL_CreateView( base, size, VFLAG_VALLOC, vprot, 0 )))
+ {
+ munmap( base, size );
+ return STATUS_NO_MEMORY;
+ }
+ }
+ }
+ else
+ {
+ /* Commit the pages */
+
+ if (!(view = VIRTUAL_FindView( base )) ||
+ ((char *)base + size > (char *)view->base + view->size)) return STATUS_NOT_MAPPED_VIEW;
+
+ if (!VIRTUAL_SetProt( view, base, size, vprot )) return STATUS_ACCESS_DENIED;
+ }
+
+ *ret = base;
+ *size_ptr = size;
+ return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ * NtFreeVirtualMemory (NTDLL.@)
+ * ZwFreeVirtualMemory (NTDLL.@)
+ */
+NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, ULONG *size_ptr, ULONG type )
+{
+ FILE_VIEW *view;
+ char *base;
+ LPVOID addr = *addr_ptr;
+ DWORD size = *size_ptr;
+
+ if (!is_current_process( process ))
+ {
+ ERR("Unsupported on other process\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ TRACE("%p %08lx %lx\n", addr, size, type );
+
+ /* Fix the parameters */
+
+ size = ROUND_SIZE( addr, size );
+ base = ROUND_ADDR( addr, page_mask );
+
+ if (!(view = VIRTUAL_FindView( base )) ||
+ (base + size > (char *)view->base + view->size) ||
+ !(view->flags & VFLAG_VALLOC))
+ return STATUS_INVALID_PARAMETER;
+
+ /* Check the type */
+
+ if (type & MEM_SYSTEM)
+ {
+ view->flags |= VFLAG_SYSTEM;
+ type &= ~MEM_SYSTEM;
+ }
+
+ if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
+ {
+ ERR("called with wrong free type flags (%08lx) !\n", type);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Free the pages */
+
+ if (type == MEM_RELEASE)
+ {
+ if (size || (base != view->base)) return STATUS_INVALID_PARAMETER;
+ VIRTUAL_DeleteView( view );
+ }
+ else
+ {
+ /* Decommit the pages by remapping zero-pages instead */
+
+ if (wine_anon_mmap( (LPVOID)base, size, VIRTUAL_GetUnixProt(0), MAP_FIXED ) != (LPVOID)base)
+ ERR( "Could not remap pages, expect trouble\n" );
+ if (!VIRTUAL_SetProt( view, base, size, 0 )) return STATUS_ACCESS_DENIED; /* FIXME */
+ }
+
+ *addr_ptr = base;
+ *size_ptr = size;
+ return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ * NtProtectVirtualMemory (NTDLL.@)
+ * ZwProtectVirtualMemory (NTDLL.@)
+ */
+NTSTATUS WINAPI NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, ULONG *size_ptr,
+ ULONG new_prot, ULONG *old_prot )
+{
+ FILE_VIEW *view;
+ char *base;
+ UINT i;
+ BYTE vprot, *p;
+ DWORD prot, size = *size_ptr;
+ LPVOID addr = *addr_ptr;
+
+ if (!is_current_process( process ))
+ {
+ ERR("Unsupported on other process\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ TRACE("%p %08lx %08lx\n", addr, size, new_prot );
+
+ /* Fix the parameters */
+
+ size = ROUND_SIZE( addr, size );
+ base = ROUND_ADDR( addr, page_mask );
+
+ if (!(view = VIRTUAL_FindView( base )) ||
+ (base + size > (char *)view->base + view->size))
+ return STATUS_INVALID_PARAMETER;
+
+ /* Make sure all the pages are committed */
+
+ p = view->prot + ((base - (char *)view->base) >> page_shift);
+ VIRTUAL_GetWin32Prot( *p, &prot, NULL );
+ for (i = size >> page_shift; i; i--, p++)
+ {
+ if (!(*p & VPROT_COMMITTED)) return STATUS_INVALID_PARAMETER;
+ }
+
+ if (old_prot) *old_prot = prot;
+ vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
+ if (!VIRTUAL_SetProt( view, base, size, vprot )) return STATUS_ACCESS_DENIED;
+
+ *addr_ptr = base;
+ *size_ptr = size;
+ return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ * NtQueryVirtualMemory (NTDLL.@)
+ * ZwQueryVirtualMemory (NTDLL.@)
+ */
+NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
+ MEMORY_INFORMATION_CLASS info_class, PVOID buffer,
+ ULONG len, ULONG *res_len )
+{
+ FILE_VIEW *view;
+ char *base, *alloc_base = 0;
+ UINT size = 0;
+ MEMORY_BASIC_INFORMATION *info = buffer;
+
+ if (info_class != MemoryBasicInformation) return STATUS_INVALID_INFO_CLASS;
+ if (addr >= ADDRESS_SPACE_LIMIT) return STATUS_WORKING_SET_LIMIT_RANGE; /* FIXME */
+
+ if (!is_current_process( process ))
+ {
+ ERR("Unsupported on other process\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ base = ROUND_ADDR( addr, page_mask );
+
+ /* Find the view containing the address */
+
+ RtlEnterCriticalSection(&csVirtual);
+ view = VIRTUAL_FirstView;
+ for (;;)
+ {
+ if (!view)
+ {
+ size = (char *)ADDRESS_SPACE_LIMIT - alloc_base;
+ break;
+ }
+ if ((char *)view->base > base)
+ {
+ size = (char *)view->base - alloc_base;
+ view = NULL;
+ break;
+ }
+ if ((char *)view->base + view->size > base)
+ {
+ alloc_base = view->base;
+ size = view->size;
+ break;
+ }
+ alloc_base = (char *)view->base + view->size;
+ view = view->next;
+ }
+ RtlLeaveCriticalSection(&csVirtual);
+
+ /* 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);
+ *res_len = sizeof(*info);
+ return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ * NtLockVirtualMemory (NTDLL.@)
+ * ZwLockVirtualMemory (NTDLL.@)
+ */
+NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, ULONG *size, ULONG unknown )
+{
+ if (!is_current_process( process ))
+ {
+ ERR("Unsupported on other process\n");
+ return STATUS_ACCESS_DENIED;
+ }
+ return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ * NtUnlockVirtualMemory (NTDLL.@)
+ * ZwUnlockVirtualMemory (NTDLL.@)
+ */
+NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, ULONG *size, ULONG unknown )
+{
+ if (!is_current_process( process ))
+ {
+ ERR("Unsupported on other process\n");
+ return STATUS_ACCESS_DENIED;
+ }
+ return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ * NtCreateSection (NTDLL.@)
+ * ZwCreateSection (NTDLL.@)
+ */
+NTSTATUS WINAPI NtCreateSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
+ const LARGE_INTEGER *size, ULONG protect,
+ ULONG sec_flags, HANDLE file )
+{
+ NTSTATUS ret;
+ BYTE vprot;
+ DWORD len = attr->ObjectName ? attr->ObjectName->Length : 0;
+
+ /* Check parameters */
+
+ if (len > MAX_PATH*sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
+
+ vprot = VIRTUAL_GetProt( protect );
+ if (sec_flags & SEC_RESERVE)
+ {
+ if (file) return STATUS_INVALID_PARAMETER;
+ }
+ else vprot |= VPROT_COMMITTED;
+ if (sec_flags & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
+ if (sec_flags & SEC_IMAGE) vprot |= VPROT_IMAGE;
+
+ /* Create the server object */
+
+ SERVER_START_REQ( create_mapping )
+ {
+ req->file_handle = file;
+ req->size_high = size ? size->s.HighPart : 0;
+ req->size_low = size ? size->s.LowPart : 0;
+ req->protect = vprot;
+ req->access = access;
+ req->inherit = (attr->Attributes & OBJ_INHERIT) != 0;
+ if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
+ ret = wine_server_call( req );
+ *handle = reply->handle;
+ }
+ SERVER_END_REQ;
+ return ret;
+}
+
+
+/***********************************************************************
+ * NtOpenSection (NTDLL.@)
+ * ZwOpenSection (NTDLL.@)
+ */
+NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
+{
+ NTSTATUS ret;
+ DWORD len = attr->ObjectName->Length;
+
+ if (len > MAX_PATH*sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
+
+ SERVER_START_REQ( open_mapping )
+ {
+ req->access = access;
+ req->inherit = (attr->Attributes & OBJ_INHERIT) != 0;
+ wine_server_add_data( req, attr->ObjectName->Buffer, len );
+ if (!(ret = wine_server_call( req ))) *handle = reply->handle;
+ }
+ SERVER_END_REQ;
+ return ret;
+}
+
+
+/***********************************************************************
+ * NtMapViewOfSection (NTDLL.@)
+ * ZwMapViewOfSection (NTDLL.@)
+ */
+NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_ptr, ULONG zero_bits,
+ ULONG commit_size, const LARGE_INTEGER *offset, ULONG *size_ptr,
+ SECTION_INHERIT inherit, ULONG alloc_type, ULONG protect )
+{
+ FILE_VIEW *view;
+ NTSTATUS res;
+ UINT size = 0;
+ int flags = MAP_PRIVATE;
+ int unix_handle = -1;
+ int prot;
+ void *base, *ptr = (void *)-1, *ret;
+ DWORD size_low, size_high, header_size, shared_size;
+ HANDLE shared_file;
+ BOOL removable;
+
+ if (!is_current_process( process ))
+ {
+ ERR("Unsupported on other process\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ TRACE("handle=%x addr=%p off=%lx%08lx size=%x access=%lx\n",
+ handle, *addr_ptr, offset->s.HighPart, offset->s.LowPart, size, protect );
+
+ /* Check parameters */
+
+ if ((offset->s.LowPart & granularity_mask) ||
+ (*addr_ptr && ((UINT_PTR)*addr_ptr & granularity_mask)))
+ return STATUS_INVALID_PARAMETER;
+
+ SERVER_START_REQ( get_mapping_info )
+ {
+ req->handle = handle;
+ res = wine_server_call( req );
+ prot = reply->protect;
+ base = reply->base;
+ size_low = reply->size_low;
+ size_high = reply->size_high;
+ header_size = reply->header_size;
+ shared_file = reply->shared_file;
+ shared_size = reply->shared_size;
+ removable = (reply->drive_type == DRIVE_REMOVABLE ||
+ reply->drive_type == DRIVE_CDROM);
+ }
+ SERVER_END_REQ;
+ if (res) goto error;
+
+ if ((res = wine_server_handle_to_fd( handle, 0, &unix_handle, NULL, NULL ))) goto error;
+
+ if (prot & VPROT_IMAGE)
+ {
+ int shared_fd = -1;
+
+ if (shared_file)
+ {
+ if ((res = wine_server_handle_to_fd( shared_file, GENERIC_READ, &shared_fd,
+ NULL, NULL ))) goto error;
+ NtClose( shared_file ); /* we no longer need it */
+ }
+ res = map_image( handle, unix_handle, base, size_low, header_size,
+ shared_fd, shared_size, removable, addr_ptr );
+ if (shared_fd != -1) close( shared_fd );
+ if (!res) *size_ptr = size_low;
+ return res;
+ }
+
+
+ if (size_high)
+ ERR("Sizes larger than 4Gb not supported\n");
+
+ if ((offset->s.LowPart >= size_low) ||
+ (*size_ptr > size_low - offset->s.LowPart))
+ {
+ res = STATUS_INVALID_PARAMETER;
+ goto error;
+ }
+ if (*size_ptr) size = ROUND_SIZE( offset->s.LowPart, *size_ptr );
+ else size = size_low - offset->s.LowPart;
+
+ switch(protect)
+ {
+ case PAGE_NOACCESS:
+ break;
+ case PAGE_READWRITE:
+ case PAGE_EXECUTE_READWRITE:
+ if (!(prot & VPROT_WRITE))
+ {
+ res = STATUS_INVALID_PARAMETER;
+ goto error;
+ }
+ flags = MAP_SHARED;
+ /* fall through */
+ case PAGE_READONLY:
+ case PAGE_WRITECOPY:
+ case PAGE_EXECUTE:
+ case PAGE_EXECUTE_READ:
+ case PAGE_EXECUTE_WRITECOPY:
+ if (prot & VPROT_READ) break;
+ /* fall through */
+ default:
+ res = STATUS_INVALID_PARAMETER;
+ goto error;
+ }
+
+ /* FIXME: If a mapping is created with SEC_RESERVE and a process,
+ * which has a view of this mapping commits some pages, they will
+ * appear commited in all other processes, which have the same
+ * view created. Since we don`t support this yet, we create the
+ * whole mapping commited.
+ */
+ prot |= VPROT_COMMITTED;
+
+ /* Reserve a properly aligned area */
+
+ if ((res = anon_mmap_aligned( addr_ptr, size, PROT_NONE, 0 ))) goto error;
+ ptr = *addr_ptr;
+
+ /* Map the file */
+
+ TRACE("handle=%x size=%x offset=%lx\n", handle, size, offset->s.LowPart );
+
+ ret = VIRTUAL_mmap( unix_handle, ptr, size, offset->s.LowPart, offset->s.HighPart,
+ VIRTUAL_GetUnixProt( prot ), flags | MAP_FIXED, &removable );
+ if (ret != ptr)
+ {
+ ERR( "VIRTUAL_mmap %p %x %lx%08lx failed\n",
+ ptr, size, offset->s.HighPart, offset->s.LowPart );
+ res = STATUS_NO_MEMORY; /* FIXME */
+ goto error;
+ }
+ if (removable) handle = 0; /* don't keep handle open on removable media */
+
+ if (!(view = VIRTUAL_CreateView( ptr, size, 0, prot, handle )))
+ {
+ res = STATUS_NO_MEMORY;
+ goto error;
+ }
+ if (unix_handle != -1) close( unix_handle );
+ *size_ptr = size;
+ return STATUS_SUCCESS;
+
+error:
+ if (unix_handle != -1) close( unix_handle );
+ if (ptr != (void *)-1) munmap( ptr, size );
+ return res;
+}
+
+
+/***********************************************************************
+ * NtUnmapViewOfSection (NTDLL.@)
+ * ZwUnmapViewOfSection (NTDLL.@)
+ */
+NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
+{
+ FILE_VIEW *view;
+ void *base = ROUND_ADDR( addr, page_mask );
+
+ if (!is_current_process( process ))
+ {
+ ERR("Unsupported on other process\n");
+ return STATUS_ACCESS_DENIED;
+ }
+ if (!(view = VIRTUAL_FindView( base )) || (base != view->base)) return STATUS_INVALID_PARAMETER;
+ VIRTUAL_DeleteView( view );
+ return STATUS_SUCCESS;
+}
+
+
+/***********************************************************************
+ * NtFlushVirtualMemory (NTDLL.@)
+ * ZwFlushVirtualMemory (NTDLL.@)
+ */
+NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
+ ULONG *size_ptr, ULONG unknown )
+{
+ FILE_VIEW *view;
+ void *addr = ROUND_ADDR( *addr_ptr, page_mask );
+
+ if (!is_current_process( process ))
+ {
+ ERR("Unsupported on other process\n");
+ return STATUS_ACCESS_DENIED;
+ }
+ if (!(view = VIRTUAL_FindView( addr ))) return STATUS_INVALID_PARAMETER;
+ if (!*size_ptr) *size_ptr = view->size;
+ *addr_ptr = addr;
+ if (!msync( addr, *size_ptr, MS_SYNC )) return STATUS_SUCCESS;
+ return STATUS_NOT_MAPPED_DATA;
+}
diff --git a/include/winbase.h b/include/winbase.h
index f65e7f3..5d290af 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -1500,10 +1500,11 @@
#define VerifyVersionInfo WINELIB_NAME_AW(VerifyVersionInfo)
LPVOID WINAPI VirtualAlloc(LPVOID,DWORD,DWORD,DWORD);
LPVOID WINAPI VirtualAllocEx(HANDLE,LPVOID,DWORD,DWORD,DWORD);
-BOOL WINAPI VirtualFree(LPVOID,DWORD,DWORD);
-BOOL WINAPI VirtualLock(LPVOID,DWORD);
-BOOL WINAPI VirtualProtect(LPVOID,DWORD,DWORD,LPDWORD);
-BOOL WINAPI VirtualProtectEx(HANDLE,LPVOID,DWORD,DWORD,LPDWORD);
+BOOL WINAPI VirtualFree(LPVOID,DWORD,DWORD);
+BOOL WINAPI VirtualFreeEx(HANDLE,LPVOID,DWORD,DWORD);
+BOOL WINAPI VirtualLock(LPVOID,DWORD);
+BOOL WINAPI VirtualProtect(LPVOID,DWORD,DWORD,LPDWORD);
+BOOL WINAPI VirtualProtectEx(HANDLE,LPVOID,DWORD,DWORD,LPDWORD);
DWORD WINAPI VirtualQuery(LPCVOID,LPMEMORY_BASIC_INFORMATION,DWORD);
DWORD WINAPI VirtualQueryEx(HANDLE,LPCVOID,LPMEMORY_BASIC_INFORMATION,DWORD);
BOOL WINAPI VirtualUnlock(LPVOID,DWORD);
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index c5d991a..0b7c4fd 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1418,6 +1418,7 @@
int size_high;
int size_low;
int protect;
+ unsigned int access;
int inherit;
obj_handle_t file_handle;
/* VARARG(name,unicode_str); */
@@ -3209,6 +3210,6 @@
struct get_window_properties_reply get_window_properties_reply;
};
-#define SERVER_PROTOCOL_VERSION 81
+#define SERVER_PROTOCOL_VERSION 82
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/winnt.h b/include/winnt.h
index 89bc850..5a1cd1a 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -3185,6 +3185,13 @@
#define THREAD_BASE_PRIORITY_MIN -2
#define THREAD_BASE_PRIORITY_IDLE -15
+#define SECTION_QUERY 0x0001
+#define SECTION_MAP_WRITE 0x0002
+#define SECTION_MAP_READ 0x0004
+#define SECTION_MAP_EXECUTE 0x0008
+#define SECTION_EXTEND_SIZE 0x0010
+#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|0x01f)
+
#define FILE_READ_DATA 0x0001 /* file & pipe */
#define FILE_LIST_DIRECTORY 0x0001 /* directory */
#define FILE_WRITE_DATA 0x0002 /* file & pipe */
diff --git a/include/winternl.h b/include/winternl.h
index 3568a36..41279a4 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -259,6 +259,11 @@
WinStationInformation = 8
} WINSTATIONINFOCLASS;
+typedef enum
+{
+ MemoryBasicInformation = 0
+} MEMORY_INFORMATION_CLASS;
+
/***********************************************************************
* IA64 specific types and data structures
*/
@@ -753,11 +758,13 @@
NTSTATUS WINAPI NtAccessCheck(PSECURITY_DESCRIPTOR,HANDLE,ACCESS_MASK,PGENERIC_MAPPING,PPRIVILEGE_SET,PULONG,PULONG,PBOOLEAN);
NTSTATUS WINAPI NtAdjustPrivilegesToken(HANDLE,BOOLEAN,PTOKEN_PRIVILEGES,DWORD,PTOKEN_PRIVILEGES,PDWORD);
+NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE,PVOID*,PVOID,ULONG*,ULONG,ULONG);
NTSTATUS WINAPI NtClearEvent(HANDLE);
NTSTATUS WINAPI NtClose(HANDLE);
NTSTATUS WINAPI NtCreateEvent(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *,BOOLEAN,BOOLEAN);
NTSTATUS WINAPI NtCreateFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG);
NTSTATUS WINAPI NtCreateKey(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES*,ULONG,const UNICODE_STRING*,ULONG,PULONG);
+NTSTATUS WINAPI NtCreateSection(HANDLE*,ACCESS_MASK,const OBJECT_ATTRIBUTES*,const LARGE_INTEGER*,ULONG,ULONG,HANDLE);
NTSTATUS WINAPI NtCreateSemaphore(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES*,ULONG,ULONG);
NTSTATUS WINAPI NtDeleteKey(HANDLE);
NTSTATUS WINAPI NtDeleteValueKey(HANDLE,const UNICODE_STRING *);
@@ -766,13 +773,19 @@
NTSTATUS WINAPI NtEnumerateKey(HANDLE,ULONG,KEY_INFORMATION_CLASS,void *,DWORD,DWORD *);
NTSTATUS WINAPI NtEnumerateValueKey(HANDLE,ULONG,KEY_VALUE_INFORMATION_CLASS,PVOID,ULONG,PULONG);
NTSTATUS WINAPI NtFlushKey(HANDLE);
+NTSTATUS WINAPI NtFlushVirtualMemory(HANDLE,LPCVOID*,ULONG*,ULONG);
+NTSTATUS WINAPI NtFreeVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG);
NTSTATUS WINAPI NtLoadKey(const OBJECT_ATTRIBUTES *,const OBJECT_ATTRIBUTES *);
+NTSTATUS WINAPI NtLockVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG);
+NTSTATUS WINAPI NtMapViewOfSection(HANDLE,HANDLE,PVOID*,ULONG,ULONG,const LARGE_INTEGER*,ULONG*,SECTION_INHERIT,ULONG,ULONG);
NTSTATUS WINAPI NtNotifyChangeKey(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,BOOLEAN,PVOID,ULONG,BOOLEAN);
NTSTATUS WINAPI NtOpenEvent(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *);
NTSTATUS WINAPI NtOpenFile(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,ULONG,ULONG);
NTSTATUS WINAPI NtOpenKey(PHANDLE,ACCESS_MASK,const OBJECT_ATTRIBUTES *);
NTSTATUS WINAPI NtOpenProcessToken(HANDLE,DWORD,HANDLE *);
+NTSTATUS WINAPI NtOpenSection(HANDLE*,ACCESS_MASK,const OBJECT_ATTRIBUTES*);
NTSTATUS WINAPI NtOpenThreadToken(HANDLE,DWORD,BOOLEAN,HANDLE *);
+NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG,ULONG*);
NTSTATUS WINAPI NtPulseEvent(HANDLE,PULONG);
NTSTATUS WINAPI NtQueryInformationProcess(HANDLE,PROCESSINFOCLASS,PVOID,ULONG,PULONG);
NTSTATUS WINAPI NtQueryInformationThread(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG);
@@ -783,6 +796,7 @@
NTSTATUS WINAPI NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS,PVOID,ULONG,PULONG);
NTSTATUS WINAPI NtQuerySystemTime(PLARGE_INTEGER);
NTSTATUS WINAPI NtQueryValueKey(HANDLE,const UNICODE_STRING *,KEY_VALUE_INFORMATION_CLASS,void *,DWORD,DWORD *);
+NTSTATUS WINAPI NtQueryVirtualMemory(HANDLE,LPCVOID,MEMORY_INFORMATION_CLASS,PVOID,ULONG,ULONG*);
void WINAPI NtRaiseException(PEXCEPTION_RECORD,PCONTEXT,BOOL);
NTSTATUS WINAPI NtReadFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,PLARGE_INTEGER,PULONG);
NTSTATUS WINAPI NtReleaseSemaphore(HANDLE,ULONG,PULONG);
@@ -797,6 +811,8 @@
NTSTATUS WINAPI NtTerminateProcess(HANDLE,LONG);
NTSTATUS WINAPI NtTerminateThread(HANDLE,LONG);
NTSTATUS WINAPI NtUnloadKey(HANDLE);
+NTSTATUS WINAPI NtUnlockVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG);
+NTSTATUS WINAPI NtUnmapViewOfSection(HANDLE,PVOID);
NTSTATUS WINAPI NtWaitForSingleObject(HANDLE,BOOLEAN,PLARGE_INTEGER);
void WINAPI RtlAcquirePebLock(void);
diff --git a/memory/virtual.c b/memory/virtual.c
index ab01a1e..32f6c5d 100644
--- a/memory/virtual.c
+++ b/memory/virtual.c
@@ -21,110 +21,25 @@
#include "config.h"
#include "wine/port.h"
-#include <assert.h>
-#include <errno.h>
-#ifdef HAVE_SYS_ERRNO_H
-#include <sys/errno.h>
-#endif
#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
+
#include "winnls.h"
#include "winbase.h"
-#include "wine/exception.h"
-#include "wine/unicode.h"
-#include "wine/library.h"
+#include "winternl.h"
#include "winerror.h"
-#include "file.h"
-#include "global.h"
-#include "wine/server.h"
+#include "wine/exception.h"
#include "msvcrt/excpt.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(virtual);
-WINE_DECLARE_DEBUG_CHANNEL(module);
-#ifndef MS_SYNC
-#define MS_SYNC 0
-#endif
-
-/* File view */
-typedef struct _FV
-{
- struct _FV *next; /* Next view */
- struct _FV *prev; /* Prev view */
- void *base; /* Base address */
- UINT size; /* Size in bytes */
- UINT flags; /* Allocation flags */
- HANDLE mapping; /* Handle to the 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-view flags */
-#define VFLAG_SYSTEM 0x01
-#define VFLAG_VALLOC 0x02 /* allocated by VirtualAlloc */
-
-/* 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;
-static CRITICAL_SECTION csVirtual = CRITICAL_SECTION_INIT("csVirtual");
-
-#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 page_size 0x1000
-#else
-static UINT page_shift;
-static UINT page_mask;
-static UINT page_size;
-#endif /* __i386__ */
-#define granularity_mask 0xffff /* Allocation granularity (usually 64k) */
-
-#define ADDRESS_SPACE_LIMIT ((void *)0xc0000000) /* top of the user address space */
-
-#define ROUND_ADDR(addr,mask) \
- ((void *)((UINT_PTR)(addr) & ~(mask)))
-
-#define ROUND_SIZE(addr,size) \
- (((UINT)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
-
-#define VIRTUAL_DEBUG_DUMP_VIEW(view) \
- if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
-
-static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, DWORD offset_low,
- DWORD offset_high, int prot, int flags, BOOL *removable );
+static unsigned int page_size;
/* filter for page-fault exceptions */
static WINE_EXCEPTION_FILTER(page_fault)
@@ -134,841 +49,6 @@
return EXCEPTION_CONTINUE_SEARCH;
}
-/***********************************************************************
- * 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 )
-{
- UINT i, count;
- char *addr = view->base;
- BYTE prot = view->prot[0];
-
- DPRINTF( "View: %p - %p", addr, addr + view->size - 1 );
- if (view->flags & VFLAG_SYSTEM)
- DPRINTF( " (system)\n" );
- else if (view->flags & VFLAG_VALLOC)
- DPRINTF( " (valloc)\n" );
- else if (view->mapping)
- DPRINTF( " %d\n", view->mapping );
- else
- DPRINTF( " (anonymous)\n");
-
- for (count = i = 1; i < view->size >> page_shift; i++, count++)
- {
- if (view->prot[i] == prot) continue;
- DPRINTF( " %p - %p %s\n",
- addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) );
- addr += (count << page_shift);
- prot = view->prot[i];
- count = 0;
- }
- if (count)
- DPRINTF( " %p - %p %s\n",
- addr, addr + (count << page_shift) - 1, VIRTUAL_GetProtStr(prot) );
-}
-
-
-/***********************************************************************
- * VIRTUAL_Dump
- */
-void VIRTUAL_Dump(void)
-{
- FILE_VIEW *view;
- DPRINTF( "\nDump of all virtual memory views:\n\n" );
- EnterCriticalSection(&csVirtual);
- view = VIRTUAL_FirstView;
- while (view)
- {
- VIRTUAL_DumpView( view );
- view = view->next;
- }
- LeaveCriticalSection(&csVirtual);
-}
-
-
-/***********************************************************************
- * VIRTUAL_FindView
- *
- * Find the view containing a given address.
- *
- * RETURNS
- * View: Success
- * NULL: Failure
- */
-static FILE_VIEW *VIRTUAL_FindView( const void *addr ) /* [in] Address */
-{
- FILE_VIEW *view;
-
- EnterCriticalSection(&csVirtual);
- view = VIRTUAL_FirstView;
- while (view)
- {
- if (view->base > addr)
- {
- view = NULL;
- break;
- }
- if ((char*)view->base + view->size > (char*)addr) break;
- view = view->next;
- }
- LeaveCriticalSection(&csVirtual);
- return view;
-}
-
-
-/***********************************************************************
- * VIRTUAL_CreateView
- *
- * Create a new view and add it in the linked list.
- */
-static FILE_VIEW *VIRTUAL_CreateView( void *base, UINT size, UINT flags,
- BYTE vprot, HANDLE mapping )
-{
- FILE_VIEW *view, *prev;
-
- /* Create the view structure */
-
- assert( !((unsigned int)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->mapping = mapping;
- view->protect = vprot;
- view->handlerProc = NULL;
- memset( view->prot, vprot, size );
-
- /* Duplicate the mapping handle */
-
- if (view->mapping &&
- !DuplicateHandle( GetCurrentProcess(), view->mapping,
- GetCurrentProcess(), &view->mapping,
- 0, FALSE, DUPLICATE_SAME_ACCESS ))
- {
- free( view );
- return NULL;
- }
-
- /* Insert it in the linked list */
-
- EnterCriticalSection(&csVirtual);
- 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;
- }
- LeaveCriticalSection(&csVirtual);
- VIRTUAL_DEBUG_DUMP_VIEW( view );
- return view;
-}
-
-
-/***********************************************************************
- * VIRTUAL_DeleteView
- * Deletes a view.
- *
- * RETURNS
- * None
- */
-static void VIRTUAL_DeleteView(
- FILE_VIEW *view /* [in] View */
-) {
- if (!(view->flags & VFLAG_SYSTEM))
- munmap( (void *)view->base, view->size );
- EnterCriticalSection(&csVirtual);
- if (view->next) view->next->prev = view->prev;
- if (view->prev) view->prev->next = view->next;
- else VIRTUAL_FirstView = view->next;
- LeaveCriticalSection(&csVirtual);
- if (view->mapping) NtClose( view->mapping );
- 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_WRITECOPY) 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 (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS;
- }
-
- 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:
- /* MSDN CreateFileMapping() states that if PAGE_WRITECOPY is given,
- * that the hFile must have been opened with GENERIC_READ and
- * GENERIC_WRITE access. This is WRONG as tests show that you
- * only need GENERIC_READ access (at least for Win9x,
- * FIXME: what about NT?). Thus, we don't put VPROT_WRITE in
- * PAGE_WRITECOPY and PAGE_EXECUTE_WRITECOPY.
- */
- vprot = VPROT_READ | 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;
- break;
- case PAGE_EXECUTE_WRITECOPY:
- /* See comment for PAGE_WRITECOPY above */
- vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY;
- 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 BOOL VIRTUAL_SetProt( FILE_VIEW *view, /* [in] Pointer to view */
- void *base, /* [in] Starting address */
- UINT size, /* [in] Size in bytes */
- BYTE vprot ) /* [in] Protections to use */
-{
- TRACE("%p-%p %s\n",
- base, (char *)base + size - 1, VIRTUAL_GetProtStr( vprot ) );
-
- if (mprotect( base, size, VIRTUAL_GetUnixProt(vprot) ))
- return FALSE; /* FIXME: last error */
-
- memset( view->prot + (((char *)base - (char *)view->base) >> page_shift),
- vprot, size >> page_shift );
- VIRTUAL_DEBUG_DUMP_VIEW( view );
- return TRUE;
-}
-
-
-/***********************************************************************
- * anon_mmap_aligned
- *
- * Create an anonymous mapping aligned to the allocation granularity.
- */
-static void *anon_mmap_aligned( void *base, unsigned int size, int prot, int flags )
-{
- void *ptr;
- unsigned int view_size = size + (base ? 0 : granularity_mask + 1);
-
- if ((ptr = wine_anon_mmap( base, view_size, prot, flags )) == (void *)-1)
- {
- /* KB: Q125713, 25-SEP-1995, "Common File Mapping Problems and
- * Platform Differences":
- * Windows NT: ERROR_INVALID_PARAMETER
- * Windows 95: ERROR_INVALID_ADDRESS.
- */
- if (errno == ENOMEM) SetLastError( ERROR_OUTOFMEMORY );
- else
- {
- if (GetVersion() & 0x80000000) /* win95 */
- SetLastError( ERROR_INVALID_ADDRESS );
- else
- SetLastError( ERROR_INVALID_PARAMETER );
- }
- return ptr;
- }
-
- if (!base)
- {
- /* Release the extra memory while keeping the range
- * starting on the granularity boundary. */
- if ((unsigned int)ptr & granularity_mask)
- {
- unsigned int extra = granularity_mask + 1 - ((unsigned int)ptr & granularity_mask);
- munmap( ptr, extra );
- ptr = (char *)ptr + extra;
- view_size -= extra;
- }
- if (view_size > size)
- munmap( (char *)ptr + size, view_size - size );
- }
- else if (ptr != base)
- {
- /* We couldn't get the address we wanted */
- munmap( ptr, view_size );
- SetLastError( ERROR_INVALID_ADDRESS );
- ptr = (void *)-1;
- }
- return ptr;
-}
-
-
-/***********************************************************************
- * do_relocations
- *
- * Apply the relocations to a mapped PE image
- */
-static int do_relocations( char *base, const IMAGE_DATA_DIRECTORY *dir,
- int delta, DWORD total_size )
-{
- IMAGE_BASE_RELOCATION *rel;
-
- TRACE_(module)( "relocating from %p-%p to %p-%p\n",
- base - delta, base - delta + total_size, base, base + total_size );
-
- for (rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress);
- ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock;
- rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock) )
- {
- char *page = base + rel->VirtualAddress;
- WORD *TypeOffset = (WORD *)(rel + 1);
- int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset);
-
- if (!count) continue;
-
- /* sanity checks */
- if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size ||
- page > base + total_size)
- {
- ERR_(module)("invalid relocation %p,%lx,%ld at %p,%lx,%lx\n",
- rel, rel->VirtualAddress, rel->SizeOfBlock,
- base, dir->VirtualAddress, dir->Size );
- return 0;
- }
-
- TRACE_(module)("%ld relocations for page %lx\n", rel->SizeOfBlock, rel->VirtualAddress);
-
- /* patching in reverse order */
- for (i = 0 ; i < count; i++)
- {
- int offset = TypeOffset[i] & 0xFFF;
- int type = TypeOffset[i] >> 12;
- switch(type)
- {
- case IMAGE_REL_BASED_ABSOLUTE:
- break;
- case IMAGE_REL_BASED_HIGH:
- *(short*)(page+offset) += HIWORD(delta);
- break;
- case IMAGE_REL_BASED_LOW:
- *(short*)(page+offset) += LOWORD(delta);
- break;
- case IMAGE_REL_BASED_HIGHLOW:
- *(int*)(page+offset) += delta;
- /* FIXME: if this is an exported address, fire up enhanced logic */
- break;
- default:
- FIXME_(module)("Unknown/unsupported fixup type %d.\n", type);
- break;
- }
- }
- }
- return 1;
-}
-
-
-/***********************************************************************
- * map_image
- *
- * Map an executable (PE format) image into memory.
- */
-static LPVOID map_image( HANDLE hmapping, int fd, char *base, DWORD total_size,
- DWORD header_size, HANDLE shared_file, DWORD shared_size,
- BOOL removable )
-{
- IMAGE_DOS_HEADER *dos;
- IMAGE_NT_HEADERS *nt;
- IMAGE_SECTION_HEADER *sec;
- IMAGE_DATA_DIRECTORY *imports;
- int i, pos;
- DWORD err = GetLastError();
- FILE_VIEW *view;
- char *ptr;
- int shared_fd = -1;
-
- SetLastError( ERROR_BAD_EXE_FORMAT ); /* generic error */
-
- /* zero-map the whole range */
-
- if (base < (char *)0x110000 || /* make sure the DOS area remains free */
- (ptr = wine_anon_mmap( base, total_size,
- PROT_READ | PROT_WRITE | PROT_EXEC, 0 )) == (char *)-1)
- {
- ptr = wine_anon_mmap( NULL, total_size,
- PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
- if (ptr == (char *)-1)
- {
- ERR_(module)("Not enough memory for module (%ld bytes)\n", total_size);
- goto error;
- }
- }
- TRACE_(module)( "mapped PE file at %p-%p\n", ptr, ptr + total_size );
-
- /* map the header */
-
- if (VIRTUAL_mmap( fd, ptr, header_size, 0, 0, PROT_READ,
- MAP_PRIVATE | MAP_FIXED, &removable ) == (char *)-1) goto error;
- dos = (IMAGE_DOS_HEADER *)ptr;
- nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
- if ((char *)(nt + 1) > ptr + header_size) goto error;
-
- sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
- if ((char *)(sec + nt->FileHeader.NumberOfSections) > ptr + header_size) goto error;
-
- imports = nt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT;
- if (!imports->Size || !imports->VirtualAddress) imports = NULL;
-
- /* check the architecture */
-
- if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
- {
- MESSAGE("Trying to load PE image for unsupported architecture (");
- switch (nt->FileHeader.Machine)
- {
- case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break;
- case IMAGE_FILE_MACHINE_I860: MESSAGE("I860"); break;
- case IMAGE_FILE_MACHINE_R3000: MESSAGE("R3000"); break;
- case IMAGE_FILE_MACHINE_R4000: MESSAGE("R4000"); break;
- case IMAGE_FILE_MACHINE_R10000: MESSAGE("R10000"); break;
- case IMAGE_FILE_MACHINE_ALPHA: MESSAGE("Alpha"); break;
- case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break;
- default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break;
- }
- MESSAGE(")\n");
- goto error;
- }
-
- /* retrieve the shared sections file */
-
- if (shared_size)
- {
- if ((shared_fd = FILE_GetUnixHandle( shared_file, GENERIC_READ )) == -1) goto error;
- CloseHandle( shared_file ); /* we no longer need it */
- shared_file = 0;
- }
-
- /* map all the sections */
-
- for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
- {
- DWORD size;
-
- /* a few sanity checks */
- size = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
- if (sec->VirtualAddress > total_size || size > total_size || size < sec->VirtualAddress)
- {
- ERR_(module)( "Section %.8s too large (%lx+%lx/%lx)\n",
- sec->Name, sec->VirtualAddress, sec->Misc.VirtualSize, total_size );
- goto error;
- }
-
- if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) &&
- (sec->Characteristics & IMAGE_SCN_MEM_WRITE))
- {
- size = ROUND_SIZE( 0, sec->Misc.VirtualSize );
- TRACE_(module)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n",
- sec->Name, ptr + sec->VirtualAddress,
- sec->PointerToRawData, pos, sec->SizeOfRawData,
- size, sec->Characteristics );
- if (VIRTUAL_mmap( shared_fd, ptr + sec->VirtualAddress, size,
- pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_SHARED|MAP_FIXED, NULL ) == (void *)-1)
- {
- ERR_(module)( "Could not map shared section %.8s\n", sec->Name );
- goto error;
- }
-
- /* check if the import directory falls inside this section */
- if (imports && imports->VirtualAddress >= sec->VirtualAddress &&
- imports->VirtualAddress < sec->VirtualAddress + size)
- {
- UINT_PTR base = imports->VirtualAddress & ~page_mask;
- UINT_PTR end = base + ROUND_SIZE( imports->VirtualAddress, imports->Size );
- if (end > sec->VirtualAddress + size) end = sec->VirtualAddress + size;
- if (end > base) VIRTUAL_mmap( shared_fd, ptr + base, end - base,
- pos, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_PRIVATE|MAP_FIXED, NULL );
- }
- pos += size;
- continue;
- }
-
- TRACE_(module)( "mapping section %.8s at %p off %lx size %lx flags %lx\n",
- sec->Name, ptr + sec->VirtualAddress,
- sec->PointerToRawData, sec->SizeOfRawData,
- sec->Characteristics );
-
- if (sec->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue;
- if (!sec->PointerToRawData || !sec->SizeOfRawData) continue;
-
- /* Note: if the section is not aligned properly VIRTUAL_mmap will magically
- * fall back to read(), so we don't need to check anything here.
- */
- if (VIRTUAL_mmap( fd, ptr + sec->VirtualAddress, sec->SizeOfRawData,
- sec->PointerToRawData, 0, PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_PRIVATE | MAP_FIXED, &removable ) == (void *)-1)
- {
- ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name );
- goto error;
- }
-
- if ((sec->SizeOfRawData < sec->Misc.VirtualSize) && (sec->SizeOfRawData & page_mask))
- {
- DWORD end = ROUND_SIZE( 0, sec->SizeOfRawData );
- if (end > sec->Misc.VirtualSize) end = sec->Misc.VirtualSize;
- TRACE_(module)("clearing %p - %p\n",
- ptr + sec->VirtualAddress + sec->SizeOfRawData,
- ptr + sec->VirtualAddress + end );
- memset( ptr + sec->VirtualAddress + sec->SizeOfRawData, 0,
- end - sec->SizeOfRawData );
- }
- }
-
-
- /* perform base relocation, if necessary */
-
- if (ptr != base)
- {
- const IMAGE_DATA_DIRECTORY *relocs;
-
- relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
- if (!relocs->VirtualAddress || !relocs->Size)
- {
- if (nt->OptionalHeader.ImageBase == 0x400000)
- ERR("Standard load address for a Win32 program (0x00400000) not available - security-patched kernel ?\n");
- else
- ERR( "FATAL: Need to relocate module from addr %lx, but there are no relocation records\n",
- nt->OptionalHeader.ImageBase );
- SetLastError( ERROR_BAD_EXE_FORMAT );
- goto error;
- }
-
- /* FIXME: If we need to relocate a system DLL (base > 2GB) we should
- * really make sure that the *new* base address is also > 2GB.
- * Some DLLs really check the MSB of the module handle :-/
- */
- if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((DWORD)base & 0x80000000))
- ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" );
-
- if (!do_relocations( ptr, relocs, ptr - base, total_size ))
- {
- SetLastError( ERROR_BAD_EXE_FORMAT );
- goto error;
- }
- }
-
- if (removable) hmapping = 0; /* don't keep handle open on removable media */
- if (!(view = VIRTUAL_CreateView( ptr, total_size, 0, VPROT_COMMITTED|VPROT_READ, hmapping )))
- {
- SetLastError( ERROR_OUTOFMEMORY );
- goto error;
- }
-
- /* set the image protections */
-
- sec = (IMAGE_SECTION_HEADER*)((char *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
- for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
- {
- DWORD size = ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
- BYTE vprot = VPROT_COMMITTED;
- if (sec->Characteristics & IMAGE_SCN_MEM_READ) vprot |= VPROT_READ;
- if (sec->Characteristics & IMAGE_SCN_MEM_WRITE) vprot |= VPROT_WRITE|VPROT_WRITECOPY;
- if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC;
-
- /* make sure the import directory is writable */
- if (imports && imports->VirtualAddress >= sec->VirtualAddress &&
- imports->VirtualAddress < sec->VirtualAddress + size)
- vprot |= VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY;
-
- VIRTUAL_SetProt( view, ptr + sec->VirtualAddress, size, vprot );
- }
-
- SetLastError( err ); /* restore last error */
- close( fd );
- if (shared_fd != -1) close( shared_fd );
- return ptr;
-
- error:
- if (ptr != (char *)-1) munmap( ptr, total_size );
- close( fd );
- if (shared_fd != -1) close( shared_fd );
- if (shared_file) CloseHandle( shared_file );
- return NULL;
-}
-
-
-/***********************************************************************
- * VIRTUAL_Init
- */
-#ifndef page_mask
-DECL_GLOBAL_CONSTRUCTOR(VIRTUAL_Init)
-{
- page_size = getpagesize();
- page_mask = page_size - 1;
- /* 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 /* page_mask */
-
-
-/***********************************************************************
- * VIRTUAL_SetFaultHandler
- */
-BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg )
-{
- FILE_VIEW *view;
-
- if (!(view = VIRTUAL_FindView( addr ))) return FALSE;
- view->handlerProc = proc;
- view->handlerArg = arg;
- return TRUE;
-}
-
-/***********************************************************************
- * VIRTUAL_HandleFault
- */
-DWORD VIRTUAL_HandleFault( LPCVOID addr )
-{
- FILE_VIEW *view = VIRTUAL_FindView( addr );
- DWORD ret = EXCEPTION_ACCESS_VIOLATION;
-
- if (view)
- {
- if (view->handlerProc)
- {
- if (view->handlerProc(view->handlerArg, addr)) ret = 0; /* handled */
- }
- else
- {
- BYTE vprot = view->prot[((char *)addr - (char *)view->base) >> page_shift];
- void *page = (void *)((UINT_PTR)addr & ~page_mask);
- char *stack = (char *)NtCurrentTeb()->stack_base + SIGNAL_STACK_SIZE + page_mask + 1;
- if (vprot & VPROT_GUARD)
- {
- VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD );
- ret = STATUS_GUARD_PAGE_VIOLATION;
- }
- /* is it inside the stack guard pages? */
- if (((char *)addr >= stack) && ((char *)addr < stack + 2*(page_mask+1)))
- ret = STATUS_STACK_OVERFLOW;
- }
- }
- return ret;
-}
-
-
-
-/***********************************************************************
- * unaligned_mmap
- *
- * Linux kernels before 2.4.x can support non page-aligned offsets, as
- * long as the offset is aligned to the filesystem block size. This is
- * a big performance gain so we want to take advantage of it.
- *
- * However, when we use 64-bit file support this doesn't work because
- * glibc rejects unaligned offsets. Also glibc 2.1.3 mmap64 is broken
- * in that it rounds unaligned offsets down to a page boundary. For
- * these reasons we do a direct system call here.
- */
-static void *unaligned_mmap( void *addr, size_t length, unsigned int prot,
- unsigned int flags, int fd, unsigned int offset_low,
- unsigned int offset_high )
-{
-#if defined(linux) && defined(__i386__) && defined(__GNUC__)
- if (!offset_high && (offset_low & page_mask))
- {
- int ret;
-
- struct
- {
- void *addr;
- unsigned int length;
- unsigned int prot;
- unsigned int flags;
- unsigned int fd;
- unsigned int offset;
- } args;
-
- args.addr = addr;
- args.length = length;
- args.prot = prot;
- args.flags = flags;
- args.fd = fd;
- args.offset = offset_low;
-
- __asm__ __volatile__("push %%ebx\n\t"
- "movl %2,%%ebx\n\t"
- "int $0x80\n\t"
- "popl %%ebx"
- : "=a" (ret)
- : "0" (90), /* SYS_mmap */
- "g" (&args) );
- if (ret < 0 && ret > -4096)
- {
- errno = -ret;
- ret = -1;
- }
- return (void *)ret;
- }
-#endif
- return mmap( addr, length, prot, flags, fd, ((off_t)offset_high << 32) | offset_low );
-}
-
-
-/***********************************************************************
- * VIRTUAL_mmap
- *
- * Wrapper for mmap() that handles anonymous mappings portably,
- * and falls back to read if mmap of a file fails.
- */
-static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size,
- DWORD offset_low, DWORD offset_high,
- int prot, int flags, BOOL *removable )
-{
- int pos;
- LPVOID ret;
- off_t offset;
- BOOL is_shared_write = FALSE;
-
- if (fd == -1) return wine_anon_mmap( start, size, prot, flags );
-
- if (prot & PROT_WRITE)
- {
-#ifdef MAP_SHARED
- if (flags & MAP_SHARED) is_shared_write = TRUE;
-#endif
-#ifdef MAP_PRIVATE
- if (!(flags & MAP_PRIVATE)) is_shared_write = TRUE;
-#endif
- }
-
- if (removable && *removable)
- {
- /* if on removable media, try using read instead of mmap */
- if (!is_shared_write) goto fake_mmap;
- *removable = FALSE;
- }
-
- if ((ret = unaligned_mmap( start, size, prot, flags, fd,
- offset_low, offset_high )) != (LPVOID)-1) return ret;
-
- /* mmap() failed; if this is because the file offset is not */
- /* page-aligned (EINVAL), or because the underlying filesystem */
- /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */
-
- if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return ret;
- if (is_shared_write) return ret; /* we cannot fake shared write mappings */
-
- fake_mmap:
- /* Reserve the memory with an anonymous mmap */
- ret = wine_anon_mmap( start, size, PROT_READ | PROT_WRITE, flags );
- if (ret == (LPVOID)-1) return ret;
- /* Now read in the file */
- offset = ((off_t)offset_high << 32) | offset_low;
- if ((pos = lseek( fd, offset, SEEK_SET )) == -1)
- {
- munmap( ret, size );
- return (LPVOID)-1;
- }
- read( fd, ret, size );
- lseek( fd, pos, SEEK_SET ); /* Restore the file pointer */
- mprotect( ret, size, prot ); /* Set the right protection */
- return ret;
-}
-
/***********************************************************************
* VirtualAlloc (KERNEL32.@)
@@ -984,98 +64,7 @@
DWORD type, /* [in] Type of allocation */
DWORD protect)/* [in] Type of access protection */
{
- FILE_VIEW *view;
- char *ptr, *base;
- BYTE vprot;
-
- TRACE("%p %08lx %lx %08lx\n", 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 = ROUND_ADDR( addr, granularity_mask );
- else
- base = ROUND_ADDR( addr, page_mask );
- size = (((UINT_PTR)addr + size + page_mask) & ~page_mask) - (UINT_PTR)base;
-
- /* disallow low 64k, wrap-around and kernel space */
- if ((base <= (char *)granularity_mask) ||
- (base + size < base) ||
- (base + size > (char *)ADDRESS_SPACE_LIMIT))
- {
- 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("MEM_TOP_DOWN ignored\n");
- type &= ~MEM_TOP_DOWN;
- }
- /* Compute the alloc type flags */
-
- if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)) ||
- (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)))
- {
- ERR("called with wrong alloc type flags (%08lx) !\n", type);
- SetLastError( ERROR_INVALID_PARAMETER );
- return NULL;
- }
- if (type & (MEM_COMMIT | MEM_SYSTEM))
- vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
- else vprot = 0;
-
- /* Reserve the memory */
-
- if ((type & MEM_RESERVE) || !base)
- {
- if (type & MEM_SYSTEM)
- {
- if (!(view = VIRTUAL_CreateView( base, size, VFLAG_VALLOC | VFLAG_SYSTEM, vprot, 0 )))
- {
- SetLastError( ERROR_OUTOFMEMORY );
- return NULL;
- }
- return (LPVOID)base;
- }
- ptr = anon_mmap_aligned( base, size, VIRTUAL_GetUnixProt( vprot ), 0 );
- if (ptr == (void *)-1) return NULL;
-
- if (!(view = VIRTUAL_CreateView( ptr, size, VFLAG_VALLOC, vprot, 0 )))
- {
- munmap( ptr, size );
- SetLastError( ERROR_OUTOFMEMORY );
- return NULL;
- }
- return ptr;
- }
-
- /* Commit the pages */
-
- if (!(view = VIRTUAL_FindView( base )) ||
- (base + size > (char *)view->base + view->size))
- {
- SetLastError( ERROR_INVALID_ADDRESS );
- return NULL;
- }
-
- if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL;
- return (LPVOID)base;
+ return VirtualAllocEx( GetCurrentProcess(), addr, size, type, protect );
}
@@ -1086,15 +75,20 @@
*/
LPVOID WINAPI VirtualAllocEx(
HANDLE hProcess, /* [in] Handle of process to do mem operation */
- 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 */
-) {
- if (MapProcessHandle( hProcess ) == GetCurrentProcessId())
- return VirtualAlloc( addr, size, type, protect );
- ERR("Unsupported on other process\n");
- return NULL;
+ 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 */
+{
+ LPVOID ret;
+ NTSTATUS status;
+
+ if ((status = NtAllocateVirtualMemory( hProcess, &ret, addr, &size, type, protect )))
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ ret = NULL;
+ }
+ return ret;
}
@@ -1111,57 +105,23 @@
DWORD size, /* [in] Size of region */
DWORD type /* [in] Type of operation */
) {
- FILE_VIEW *view;
- char *base;
+ return VirtualFreeEx( GetCurrentProcess(), addr, size, type );
+}
- TRACE("%p %08lx %lx\n", addr, size, type );
- /* Fix the parameters */
-
- size = ROUND_SIZE( addr, size );
- base = ROUND_ADDR( addr, page_mask );
-
- if (!(view = VIRTUAL_FindView( base )) ||
- (base + size > (char *)view->base + view->size) ||
- !(view->flags & VFLAG_VALLOC))
- {
- SetLastError( ERROR_INVALID_PARAMETER );
- return FALSE;
- }
-
- /* Check the type */
-
- if (type & MEM_SYSTEM)
- {
- view->flags |= VFLAG_SYSTEM;
- type &= ~MEM_SYSTEM;
- }
-
- if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
- {
- ERR("called with wrong free type flags (%08lx) !\n", type);
- 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 by remapping zero-pages instead */
-
- if (wine_anon_mmap( (LPVOID)base, size, VIRTUAL_GetUnixProt(0), MAP_FIXED ) != (LPVOID)base)
- ERR( "Could not remap pages, expect trouble\n" );
- return VIRTUAL_SetProt( view, base, size, 0 );
+/***********************************************************************
+ * VirtualFreeEx (KERNEL32.@)
+ * Release or decommits a region of pages in virtual address space.
+ *
+ * RETURNS
+ * TRUE: Success
+ * FALSE: Failure
+ */
+BOOL WINAPI VirtualFreeEx( HANDLE process, LPVOID addr, DWORD size, DWORD type )
+{
+ NTSTATUS status = NtFreeVirtualMemory( process, &addr, &size, type );
+ if (status) SetLastError( RtlNtStatusToDosError(status) );
+ return !status;
}
@@ -1176,11 +136,12 @@
* TRUE: Success
* FALSE: Failure
*/
-BOOL 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;
+BOOL WINAPI VirtualLock( LPVOID addr, /* [in] Address of first byte of range to lock */
+ DWORD size ) /* [in] Number of bytes in range to lock */
+{
+ NTSTATUS status = NtLockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
+ if (status) SetLastError( RtlNtStatusToDosError(status) );
+ return !status;
}
@@ -1195,11 +156,12 @@
* TRUE: Success
* FALSE: Failure
*/
-BOOL WINAPI VirtualUnlock(
- LPVOID addr, /* [in] Address of first byte of range */
- DWORD size /* [in] Number of bytes in range */
-) {
- return TRUE;
+BOOL WINAPI VirtualUnlock( LPVOID addr, /* [in] Address of first byte of range */
+ DWORD size ) /* [in] Number of bytes in range */
+{
+ NTSTATUS status = NtUnlockVirtualMemory( GetCurrentProcess(), &addr, &size, 1 );
+ if (status) SetLastError( RtlNtStatusToDosError(status) );
+ return !status;
}
@@ -1217,42 +179,7 @@
DWORD new_prot, /* [in] Desired access protection */
LPDWORD old_prot /* [out] Address of variable to get old protection */
) {
- FILE_VIEW *view;
- char *base;
- UINT i;
- BYTE vprot, *p;
- DWORD prot;
-
- TRACE("%p %08lx %08lx\n", addr, size, new_prot );
-
- /* Fix the parameters */
-
- size = ROUND_SIZE( addr, size );
- base = ROUND_ADDR( addr, page_mask );
-
- if (!(view = VIRTUAL_FindView( base )) ||
- (base + size > (char *)view->base + view->size))
- {
- SetLastError( ERROR_INVALID_PARAMETER );
- return FALSE;
- }
-
- /* Make sure all the pages are committed */
-
- p = view->prot + ((base - (char *)view->base) >> page_shift);
- VIRTUAL_GetWin32Prot( *p, &prot, NULL );
- for (i = size >> page_shift; i; i--, p++)
- {
- if (!(*p & VPROT_COMMITTED))
- {
- SetLastError( ERROR_INVALID_PARAMETER );
- return FALSE;
- }
- }
-
- if (old_prot) *old_prot = prot;
- vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
- return VIRTUAL_SetProt( view, base, size, vprot );
+ return VirtualProtectEx( GetCurrentProcess(), addr, size, new_prot, old_prot );
}
@@ -1266,16 +193,15 @@
* FALSE: Failure
*/
BOOL WINAPI VirtualProtectEx(
- HANDLE handle, /* [in] Handle of process */
+ HANDLE process, /* [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 */ )
{
- if (MapProcessHandle( handle ) == GetCurrentProcessId())
- return VirtualProtect( addr, size, new_prot, old_prot );
- ERR("Unsupported on other process\n");
- return FALSE;
+ NTSTATUS status = NtProtectVirtualMemory( process, &addr, &size, new_prot, old_prot );
+ if (status) SetLastError( RtlNtStatusToDosError(status) );
+ return !status;
}
@@ -1292,65 +218,7 @@
LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
DWORD len /* [in] Size of buffer */
) {
- FILE_VIEW *view;
- char *base, *alloc_base = 0;
- UINT size = 0;
-
- if (addr >= ADDRESS_SPACE_LIMIT) return 0;
-
- base = ROUND_ADDR( addr, page_mask );
-
- /* Find the view containing the address */
-
- EnterCriticalSection(&csVirtual);
- view = VIRTUAL_FirstView;
- for (;;)
- {
- if (!view)
- {
- size = (char *)ADDRESS_SPACE_LIMIT - alloc_base;
- break;
- }
- if ((char *)view->base > base)
- {
- size = (char *)view->base - alloc_base;
- view = NULL;
- break;
- }
- if ((char *)view->base + view->size > base)
- {
- alloc_base = view->base;
- size = view->size;
- break;
- }
- alloc_base = (char *)view->base + view->size;
- view = view->next;
- }
- LeaveCriticalSection(&csVirtual);
-
- /* 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);
+ return VirtualQueryEx( GetCurrentProcess(), addr, info, len );
}
@@ -1363,15 +231,277 @@
* Number of bytes returned in information buffer
*/
DWORD WINAPI VirtualQueryEx(
- HANDLE handle, /* [in] Handle of process */
+ HANDLE process, /* [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 */ )
{
- if (MapProcessHandle( handle ) == GetCurrentProcessId())
- return VirtualQuery( addr, info, len );
- ERR("Unsupported on other process\n");
- return 0;
+ DWORD ret;
+ NTSTATUS status;
+
+ if ((status = NtQueryVirtualMemory( process, addr, MemoryBasicInformation, info, len, &ret )))
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ ret = 0;
+ }
+ return ret;
+}
+
+
+/***********************************************************************
+ * CreateFileMappingA (KERNEL32.@)
+ * Creates a named or unnamed file-mapping object for the specified file
+ *
+ * RETURNS
+ * Handle: Success
+ * 0: Mapping object does not exist
+ * NULL: Failure
+ */
+HANDLE WINAPI CreateFileMappingA(
+ HANDLE 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 */ )
+{
+ WCHAR buffer[MAX_PATH];
+
+ if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL );
+
+ if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
+ {
+ SetLastError( ERROR_FILENAME_EXCED_RANGE );
+ return 0;
+ }
+ return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer );
+}
+
+
+/***********************************************************************
+ * CreateFileMappingW (KERNEL32.@)
+ * See CreateFileMappingA
+ */
+HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa,
+ DWORD protect, DWORD size_high,
+ DWORD size_low, LPCWSTR name )
+{
+ static const int sec_flags = SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE;
+
+ HANDLE ret;
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING nameW;
+ NTSTATUS status;
+ DWORD access, sec_type;
+ LARGE_INTEGER size;
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.ObjectName = NULL;
+ attr.Attributes = (sa && sa->bInheritHandle) ? OBJ_INHERIT : 0;
+ attr.SecurityDescriptor = sa ? sa->lpSecurityDescriptor : NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ if (name)
+ {
+ RtlInitUnicodeString( &nameW, name );
+ attr.ObjectName = &nameW;
+ }
+
+ sec_type = protect & sec_flags;
+ protect &= ~sec_flags;
+ if (!sec_type) sec_type = SEC_COMMIT;
+
+ switch(protect)
+ {
+ case 0:
+ case PAGE_READONLY:
+ case PAGE_WRITECOPY:
+ access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
+ break;
+ case PAGE_READWRITE:
+ access = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE;
+ break;
+ default:
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return 0;
+ }
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ hFile = 0;
+ if (!size_low && !size_high)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return 0;
+ }
+ }
+
+ size.s.LowPart = size_low;
+ size.s.HighPart = size_high;
+
+ status = NtCreateSection( &ret, access, &attr, &size, protect, sec_type, hFile );
+ SetLastError( RtlNtStatusToDosError(status) );
+ return ret;
+}
+
+
+/***********************************************************************
+ * OpenFileMappingA (KERNEL32.@)
+ * Opens a named file-mapping object.
+ *
+ * RETURNS
+ * Handle: Success
+ * NULL: Failure
+ */
+HANDLE WINAPI OpenFileMappingA(
+ DWORD access, /* [in] Access mode */
+ BOOL inherit, /* [in] Inherit flag */
+ LPCSTR name ) /* [in] Name of file-mapping object */
+{
+ WCHAR buffer[MAX_PATH];
+
+ if (!name) return OpenFileMappingW( access, inherit, NULL );
+
+ if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
+ {
+ SetLastError( ERROR_FILENAME_EXCED_RANGE );
+ return 0;
+ }
+ return OpenFileMappingW( access, inherit, buffer );
+}
+
+
+/***********************************************************************
+ * OpenFileMappingW (KERNEL32.@)
+ * See OpenFileMappingA
+ */
+HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
+{
+ OBJECT_ATTRIBUTES attr;
+ UNICODE_STRING nameW;
+ HANDLE ret;
+ NTSTATUS status;
+
+ if (!name)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return 0;
+ }
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.ObjectName = &nameW;
+ attr.Attributes = inherit ? OBJ_INHERIT : 0;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ RtlInitUnicodeString( &nameW, name );
+
+ if (access == FILE_MAP_COPY) access = FILE_MAP_READ;
+
+ if ((status = NtOpenSection( &ret, access, &attr )))
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ ret = 0;
+ }
+ return ret;
+}
+
+
+/***********************************************************************
+ * MapViewOfFile (KERNEL32.@)
+ * Maps a view of a file into the address space
+ *
+ * RETURNS
+ * Starting address of mapped view
+ * NULL: Failure
+ */
+LPVOID WINAPI MapViewOfFile(
+ HANDLE 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.@)
+ * Maps a view of a file into the address space
+ *
+ * RETURNS
+ * Starting address of mapped view
+ * NULL: Failure
+ */
+LPVOID WINAPI MapViewOfFileEx(
+ HANDLE 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 */
+) {
+ NTSTATUS status;
+ LARGE_INTEGER offset;
+ ULONG protect;
+
+ offset.s.LowPart = offset_low;
+ offset.s.HighPart = offset_high;
+
+ if (access & FILE_MAP_WRITE) protect = PAGE_READWRITE;
+ else if (access & FILE_MAP_READ) protect = PAGE_READONLY;
+ else if (access & FILE_MAP_COPY) protect = PAGE_WRITECOPY;
+ else protect = PAGE_NOACCESS;
+
+ if ((status = NtMapViewOfSection( handle, GetCurrentProcess(), &addr, 0, 0, &offset,
+ &count, ViewShare, 0, protect )))
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ addr = NULL;
+ }
+ return addr;
+}
+
+
+/***********************************************************************
+ * UnmapViewOfFile (KERNEL32.@)
+ * Unmaps a mapped view of a file.
+ *
+ * NOTES
+ * Should addr be an LPCVOID?
+ *
+ * RETURNS
+ * TRUE: Success
+ * FALSE: Failure
+ */
+BOOL WINAPI UnmapViewOfFile( LPVOID addr ) /* [in] Address where mapped view begins */
+{
+ NTSTATUS status = NtUnmapViewOfSection( GetCurrentProcess(), addr );
+ if (status) SetLastError( RtlNtStatusToDosError(status) );
+ return !status;
+}
+
+
+/***********************************************************************
+ * FlushViewOfFile (KERNEL32.@)
+ * Writes to the disk a byte range within a mapped view of a file
+ *
+ * RETURNS
+ * TRUE: Success
+ * FALSE: Failure
+ */
+BOOL WINAPI FlushViewOfFile( LPCVOID base, /* [in] Start address of byte range to flush */
+ DWORD size ) /* [in] Number of bytes in range */
+{
+ NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
+ if (status)
+ {
+ if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
+ else SetLastError( RtlNtStatusToDosError(status) );
+ }
+ return !status;
}
@@ -1387,6 +517,7 @@
UINT size ) /* [in] Size of block */
{
if (!size) return FALSE; /* handle 0 size case w/o reference */
+ if (!page_size) page_size = getpagesize();
__TRY
{
volatile const char *p = ptr;
@@ -1420,6 +551,7 @@
UINT size ) /* [in] Size of block in bytes */
{
if (!size) return FALSE; /* handle 0 size case w/o reference */
+ if (!page_size) page_size = getpagesize();
__TRY
{
volatile char *p = ptr;
@@ -1518,350 +650,3 @@
__ENDTRY
return FALSE;
}
-
-
-/***********************************************************************
- * CreateFileMappingA (KERNEL32.@)
- * Creates a named or unnamed file-mapping object for the specified file
- *
- * RETURNS
- * Handle: Success
- * 0: Mapping object does not exist
- * NULL: Failure
- */
-HANDLE WINAPI CreateFileMappingA(
- HANDLE 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 */ )
-{
- WCHAR buffer[MAX_PATH];
-
- if (!name) return CreateFileMappingW( hFile, sa, protect, size_high, size_low, NULL );
-
- if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
- {
- SetLastError( ERROR_FILENAME_EXCED_RANGE );
- return 0;
- }
- return CreateFileMappingW( hFile, sa, protect, size_high, size_low, buffer );
-}
-
-
-/***********************************************************************
- * CreateFileMappingW (KERNEL32.@)
- * See CreateFileMappingA
- */
-HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa,
- DWORD protect, DWORD size_high,
- DWORD size_low, LPCWSTR name )
-{
- HANDLE ret;
- BYTE vprot;
- DWORD len = name ? strlenW(name) : 0;
-
- /* Check parameters */
-
- TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
- hFile, sa, protect, size_high, size_low, debugstr_w(name) );
-
- if (len > MAX_PATH)
- {
- SetLastError( ERROR_FILENAME_EXCED_RANGE );
- return 0;
- }
-
- vprot = VIRTUAL_GetProt( protect );
- if (protect & SEC_RESERVE)
- {
- if (hFile != INVALID_HANDLE_VALUE)
- {
- SetLastError( ERROR_INVALID_PARAMETER );
- return 0;
- }
- }
- else vprot |= VPROT_COMMITTED;
- if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
- if (protect & SEC_IMAGE) vprot |= VPROT_IMAGE;
-
- /* Create the server object */
-
- if (hFile == INVALID_HANDLE_VALUE) hFile = 0;
- SERVER_START_REQ( create_mapping )
- {
- req->file_handle = hFile;
- req->size_high = size_high;
- req->size_low = size_low;
- req->protect = vprot;
- req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
- wine_server_add_data( req, name, len * sizeof(WCHAR) );
- SetLastError(0);
- wine_server_call_err( req );
- ret = reply->handle;
- }
- SERVER_END_REQ;
- return ret;
-}
-
-
-/***********************************************************************
- * OpenFileMappingA (KERNEL32.@)
- * Opens a named file-mapping object.
- *
- * RETURNS
- * Handle: Success
- * NULL: Failure
- */
-HANDLE WINAPI OpenFileMappingA(
- DWORD access, /* [in] Access mode */
- BOOL inherit, /* [in] Inherit flag */
- LPCSTR name ) /* [in] Name of file-mapping object */
-{
- WCHAR buffer[MAX_PATH];
-
- if (!name) return OpenFileMappingW( access, inherit, NULL );
-
- if (!MultiByteToWideChar( CP_ACP, 0, name, -1, buffer, MAX_PATH ))
- {
- SetLastError( ERROR_FILENAME_EXCED_RANGE );
- return 0;
- }
- return OpenFileMappingW( access, inherit, buffer );
-}
-
-
-/***********************************************************************
- * OpenFileMappingW (KERNEL32.@)
- * See OpenFileMappingA
- */
-HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
-{
- HANDLE ret;
- DWORD len = name ? strlenW(name) : 0;
- if (len >= MAX_PATH)
- {
- SetLastError( ERROR_FILENAME_EXCED_RANGE );
- return 0;
- }
- SERVER_START_REQ( open_mapping )
- {
- req->access = access;
- req->inherit = inherit;
- wine_server_add_data( req, name, len * sizeof(WCHAR) );
- wine_server_call_err( req );
- ret = reply->handle;
- }
- SERVER_END_REQ;
- return ret;
-}
-
-
-/***********************************************************************
- * MapViewOfFile (KERNEL32.@)
- * Maps a view of a file into the address space
- *
- * RETURNS
- * Starting address of mapped view
- * NULL: Failure
- */
-LPVOID WINAPI MapViewOfFile(
- HANDLE 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.@)
- * Maps a view of a file into the address space
- *
- * RETURNS
- * Starting address of mapped view
- * NULL: Failure
- */
-LPVOID WINAPI MapViewOfFileEx(
- HANDLE 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_VIEW *view;
- UINT size = 0;
- int flags = MAP_PRIVATE;
- int unix_handle = -1;
- int prot, res;
- void *base, *ptr = (void *)-1, *ret;
- DWORD size_low, size_high, header_size, shared_size;
- HANDLE shared_file;
- BOOL removable;
-
- /* Check parameters */
-
- if ((offset_low & granularity_mask) ||
- (addr && ((UINT_PTR)addr & granularity_mask)))
- {
- SetLastError( ERROR_INVALID_PARAMETER );
- return NULL;
- }
-
- SERVER_START_REQ( get_mapping_info )
- {
- req->handle = handle;
- res = wine_server_call_err( req );
- prot = reply->protect;
- base = reply->base;
- size_low = reply->size_low;
- size_high = reply->size_high;
- header_size = reply->header_size;
- shared_file = reply->shared_file;
- shared_size = reply->shared_size;
- removable = (reply->drive_type == DRIVE_REMOVABLE ||
- reply->drive_type == DRIVE_CDROM);
- }
- SERVER_END_REQ;
- if (res) goto error;
-
- if ((unix_handle = FILE_GetUnixHandle( handle, 0 )) == -1) goto error;
-
- if (prot & VPROT_IMAGE)
- return map_image( handle, unix_handle, base, size_low, header_size,
- shared_file, shared_size, removable );
-
-
- if (size_high)
- ERR("Sizes larger than 4Gb not supported\n");
-
- if ((offset_low >= size_low) ||
- (count > size_low - offset_low))
- {
- SetLastError( ERROR_INVALID_PARAMETER );
- goto error;
- }
- if (count) size = ROUND_SIZE( offset_low, count );
- else size = size_low - offset_low;
-
- switch(access)
- {
- case FILE_MAP_ALL_ACCESS:
- case FILE_MAP_WRITE:
- case FILE_MAP_WRITE | FILE_MAP_READ:
- if (!(prot & 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 (prot & VPROT_READ) break;
- /* fall through */
- default:
- SetLastError( ERROR_INVALID_PARAMETER );
- goto error;
- }
-
- /* FIXME: If a mapping is created with SEC_RESERVE and a process,
- * which has a view of this mapping commits some pages, they will
- * appear commited in all other processes, which have the same
- * view created. Since we don`t support this yet, we create the
- * whole mapping commited.
- */
- prot |= VPROT_COMMITTED;
-
- /* Reserve a properly aligned area */
-
- if ((ptr = anon_mmap_aligned( addr, size, PROT_NONE, 0 )) == (void *)-1) goto error;
-
- /* Map the file */
-
- TRACE("handle=%x size=%x offset=%lx\n", handle, size, offset_low );
-
- ret = VIRTUAL_mmap( unix_handle, ptr, size, offset_low, offset_high,
- VIRTUAL_GetUnixProt( prot ), flags | MAP_FIXED, &removable );
- if (ret != ptr)
- {
- ERR( "VIRTUAL_mmap %p %x %lx%08lx failed\n", ptr, size, offset_high, offset_low );
- goto error;
- }
- if (removable) handle = 0; /* don't keep handle open on removable media */
-
- if (!(view = VIRTUAL_CreateView( ptr, size, 0, prot, handle )))
- {
- SetLastError( ERROR_OUTOFMEMORY );
- goto error;
- }
- if (unix_handle != -1) close( unix_handle );
- return ptr;
-
-error:
- if (unix_handle != -1) close( unix_handle );
- if (ptr != (void *)-1) munmap( ptr, size );
- return NULL;
-}
-
-
-/***********************************************************************
- * FlushViewOfFile (KERNEL32.@)
- * Writes to the disk a byte range within a mapped view of a file
- *
- * RETURNS
- * TRUE: Success
- * FALSE: Failure
- */
-BOOL WINAPI FlushViewOfFile(
- LPCVOID base, /* [in] Start address of byte range to flush */
- DWORD cbFlush /* [in] Number of bytes in range */
-) {
- FILE_VIEW *view;
- void *addr = ROUND_ADDR( base, page_mask );
-
- TRACE("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( addr, cbFlush, MS_SYNC )) return TRUE;
- SetLastError( ERROR_INVALID_PARAMETER );
- return FALSE;
-}
-
-
-/***********************************************************************
- * UnmapViewOfFile (KERNEL32.@)
- * Unmaps a mapped view of a file.
- *
- * NOTES
- * Should addr be an LPCVOID?
- *
- * RETURNS
- * TRUE: Success
- * FALSE: Failure
- */
-BOOL WINAPI UnmapViewOfFile(
- LPVOID addr /* [in] Address where mapped view begins */
-) {
- FILE_VIEW *view;
- void *base = ROUND_ADDR( addr, page_mask );
- if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
- {
- SetLastError( ERROR_INVALID_PARAMETER );
- return FALSE;
- }
- VIRTUAL_DeleteView( view );
- return TRUE;
-}
diff --git a/server/mapping.c b/server/mapping.c
index 0c7e4d9..d9e79c6 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -375,9 +375,7 @@
req->protect, req->file_handle,
get_req_data(), get_req_data_size() )))
{
- int access = FILE_MAP_ALL_ACCESS;
- if (!(req->protect & VPROT_WRITE)) access &= ~FILE_MAP_WRITE;
- reply->handle = alloc_handle( current->process, obj, access, req->inherit );
+ reply->handle = alloc_handle( current->process, obj, req->access, req->inherit );
release_object( obj );
}
}
diff --git a/server/protocol.def b/server/protocol.def
index 9d4f8f3..fd526e6 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1043,6 +1043,7 @@
int size_high; /* mapping size */
int size_low; /* mapping size */
int protect; /* protection flags (see below) */
+ unsigned int access; /* wanted access rights */
int inherit; /* inherit flag */
obj_handle_t file_handle; /* file handle */
VARARG(name,unicode_str); /* object name */
diff --git a/server/trace.c b/server/trace.c
index c96863d..864e146 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1213,6 +1213,7 @@
fprintf( stderr, " size_high=%d,", req->size_high );
fprintf( stderr, " size_low=%d,", req->size_low );
fprintf( stderr, " protect=%d,", req->protect );
+ fprintf( stderr, " access=%08x,", req->access );
fprintf( stderr, " inherit=%d,", req->inherit );
fprintf( stderr, " file_handle=%d,", req->file_handle );
fprintf( stderr, " name=" );