Added an unknown VxD error code.
[wine] / memory / virtual.c
1 /*
2  * Win32 virtual memory functions
3  *
4  * Copyright 1997 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include <assert.h>
10 #include <errno.h>
11 #ifdef HAVE_SYS_ERRNO_H
12 #include <sys/errno.h>
13 #endif
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/types.h>
20 #ifdef HAVE_SYS_MMAN_H
21 #include <sys/mman.h>
22 #endif
23 #include "winnls.h"
24 #include "winbase.h"
25 #include "wine/exception.h"
26 #include "wine/unicode.h"
27 #include "wine/library.h"
28 #include "wine/port.h"
29 #include "winerror.h"
30 #include "file.h"
31 #include "global.h"
32 #include "server.h"
33 #include "debugtools.h"
34
35 DEFAULT_DEBUG_CHANNEL(virtual);
36 DECLARE_DEBUG_CHANNEL(module);
37
38 #ifndef MS_SYNC
39 #define MS_SYNC 0
40 #endif
41
42 /* File view */
43 typedef struct _FV
44 {
45     struct _FV   *next;        /* Next view */
46     struct _FV   *prev;        /* Prev view */
47     UINT        base;        /* Base address */
48     UINT        size;        /* Size in bytes */
49     UINT        flags;       /* Allocation flags */
50     HANDLE      mapping;     /* Handle to the file mapping */
51     HANDLERPROC   handlerProc; /* Fault handler */
52     LPVOID        handlerArg;  /* Fault handler argument */
53     BYTE          protect;     /* Protection for all pages at allocation time */
54     BYTE          prot[1];     /* Protection byte for each page */
55 } FILE_VIEW;
56
57 /* Per-view flags */
58 #define VFLAG_SYSTEM     0x01
59 #define VFLAG_VALLOC     0x02  /* allocated by VirtualAlloc */
60
61 /* Conversion from VPROT_* to Win32 flags */
62 static const BYTE VIRTUAL_Win32Flags[16] =
63 {
64     PAGE_NOACCESS,              /* 0 */
65     PAGE_READONLY,              /* READ */
66     PAGE_READWRITE,             /* WRITE */
67     PAGE_READWRITE,             /* READ | WRITE */
68     PAGE_EXECUTE,               /* EXEC */
69     PAGE_EXECUTE_READ,          /* READ | EXEC */
70     PAGE_EXECUTE_READWRITE,     /* WRITE | EXEC */
71     PAGE_EXECUTE_READWRITE,     /* READ | WRITE | EXEC */
72     PAGE_WRITECOPY,             /* WRITECOPY */
73     PAGE_WRITECOPY,             /* READ | WRITECOPY */
74     PAGE_WRITECOPY,             /* WRITE | WRITECOPY */
75     PAGE_WRITECOPY,             /* READ | WRITE | WRITECOPY */
76     PAGE_EXECUTE_WRITECOPY,     /* EXEC | WRITECOPY */
77     PAGE_EXECUTE_WRITECOPY,     /* READ | EXEC | WRITECOPY */
78     PAGE_EXECUTE_WRITECOPY,     /* WRITE | EXEC | WRITECOPY */
79     PAGE_EXECUTE_WRITECOPY      /* READ | WRITE | EXEC | WRITECOPY */
80 };
81
82
83 static FILE_VIEW *VIRTUAL_FirstView;
84 static CRITICAL_SECTION csVirtual = CRITICAL_SECTION_INIT;
85
86 #ifdef __i386__
87 /* These are always the same on an i386, and it will be faster this way */
88 # define page_mask  0xfff
89 # define page_shift 12
90 # define page_size  0x1000
91 #else
92 static UINT page_shift;
93 static UINT page_mask;
94 static UINT page_size;
95 #endif  /* __i386__ */
96 #define granularity_mask 0xffff  /* Allocation granularity (usually 64k) */
97
98 #define ROUND_ADDR(addr) \
99    ((UINT)(addr) & ~page_mask)
100
101 #define ROUND_SIZE(addr,size) \
102    (((UINT)(size) + ((UINT)(addr) & page_mask) + page_mask) & ~page_mask)
103
104 #define VIRTUAL_DEBUG_DUMP_VIEW(view) \
105    if (!TRACE_ON(virtual)); else VIRTUAL_DumpView(view)
106
107 static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size, DWORD offset, int prot, int flags );
108
109 /* filter for page-fault exceptions */
110 static WINE_EXCEPTION_FILTER(page_fault)
111 {
112     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
113         return EXCEPTION_EXECUTE_HANDLER;
114     return EXCEPTION_CONTINUE_SEARCH;
115 }
116
117 /***********************************************************************
118  *           VIRTUAL_GetProtStr
119  */
120 static const char *VIRTUAL_GetProtStr( BYTE prot )
121 {
122     static char buffer[6];
123     buffer[0] = (prot & VPROT_COMMITTED) ? 'c' : '-';
124     buffer[1] = (prot & VPROT_GUARD) ? 'g' : '-';
125     buffer[2] = (prot & VPROT_READ) ? 'r' : '-';
126     buffer[3] = (prot & VPROT_WRITE) ?
127                     ((prot & VPROT_WRITECOPY) ? 'w' : 'W') : '-';
128     buffer[4] = (prot & VPROT_EXEC) ? 'x' : '-';
129     buffer[5] = 0;
130     return buffer;
131 }
132
133
134 /***********************************************************************
135  *           VIRTUAL_DumpView
136  */
137 static void VIRTUAL_DumpView( FILE_VIEW *view )
138 {
139     UINT i, count;
140     UINT addr = view->base;
141     BYTE prot = view->prot[0];
142
143     DPRINTF( "View: %08x - %08x",
144              view->base, view->base + view->size - 1 );
145     if (view->flags & VFLAG_SYSTEM)
146         DPRINTF( " (system)\n" );
147     else if (view->flags & VFLAG_VALLOC)
148         DPRINTF( " (valloc)\n" );
149     else if (view->mapping)
150         DPRINTF( " %d\n", view->mapping );
151     else
152         DPRINTF( " (anonymous)\n");
153
154     for (count = i = 1; i < view->size >> page_shift; i++, count++)
155     {
156         if (view->prot[i] == prot) continue;
157         DPRINTF( "      %08x - %08x %s\n",
158               addr, addr + (count << page_shift) - 1,
159               VIRTUAL_GetProtStr(prot) );
160         addr += (count << page_shift);
161         prot = view->prot[i];
162         count = 0;
163     }
164     if (count)
165         DPRINTF( "      %08x - %08x %s\n",
166               addr, addr + (count << page_shift) - 1,
167               VIRTUAL_GetProtStr(prot) );
168 }
169
170
171 /***********************************************************************
172  *           VIRTUAL_Dump
173  */
174 void VIRTUAL_Dump(void)
175 {
176     FILE_VIEW *view;
177     DPRINTF( "\nDump of all virtual memory views:\n\n" );
178     EnterCriticalSection(&csVirtual);
179     view = VIRTUAL_FirstView;
180     while (view)
181     {
182         VIRTUAL_DumpView( view );
183         view = view->next;
184     }
185     LeaveCriticalSection(&csVirtual);
186 }
187
188
189 /***********************************************************************
190  *           VIRTUAL_FindView
191  *
192  * Find the view containing a given address.
193  *
194  * RETURNS
195  *      View: Success
196  *      NULL: Failure
197  */
198 static FILE_VIEW *VIRTUAL_FindView(
199                   UINT addr /* [in] Address */
200 ) {
201     FILE_VIEW *view;
202
203     EnterCriticalSection(&csVirtual);
204     view = VIRTUAL_FirstView;
205     while (view)
206     {
207         if (view->base > addr)
208         {
209             view = NULL;
210             break;
211         }
212         if (view->base + view->size > addr) break;
213         view = view->next;
214     }
215     LeaveCriticalSection(&csVirtual);
216     return view;
217 }
218
219
220 /***********************************************************************
221  *           VIRTUAL_CreateView
222  *
223  * Create a new view and add it in the linked list.
224  */
225 static FILE_VIEW *VIRTUAL_CreateView( UINT base, UINT size, UINT flags,
226                                       BYTE vprot, HANDLE mapping )
227 {
228     FILE_VIEW *view, *prev;
229
230     /* Create the view structure */
231
232     assert( !(base & page_mask) );
233     assert( !(size & page_mask) );
234     size >>= page_shift;
235     if (!(view = (FILE_VIEW *)malloc( sizeof(*view) + size - 1 ))) return NULL;
236     view->base    = base;
237     view->size    = size << page_shift;
238     view->flags   = flags;
239     view->mapping = mapping;
240     view->protect = vprot;
241     view->handlerProc = NULL;
242     memset( view->prot, vprot, size );
243
244     /* Duplicate the mapping handle */
245
246     if (view->mapping &&
247         !DuplicateHandle( GetCurrentProcess(), view->mapping,
248                           GetCurrentProcess(), &view->mapping,
249                           0, FALSE, DUPLICATE_SAME_ACCESS ))
250     {
251         free( view );
252         return NULL;
253     }
254
255     /* Insert it in the linked list */
256
257     EnterCriticalSection(&csVirtual);
258     if (!VIRTUAL_FirstView || (VIRTUAL_FirstView->base > base))
259     {
260         view->next = VIRTUAL_FirstView;
261         view->prev = NULL;
262         if (view->next) view->next->prev = view;
263         VIRTUAL_FirstView = view;
264     }
265     else
266     {
267         prev = VIRTUAL_FirstView;
268         while (prev->next && (prev->next->base < base)) prev = prev->next;
269         view->next = prev->next;
270         view->prev = prev;
271         if (view->next) view->next->prev = view;
272         prev->next  = view;
273     }
274     LeaveCriticalSection(&csVirtual);
275     VIRTUAL_DEBUG_DUMP_VIEW( view );
276     return view;
277 }
278
279
280 /***********************************************************************
281  *           VIRTUAL_DeleteView
282  * Deletes a view.
283  *
284  * RETURNS
285  *      None
286  */
287 static void VIRTUAL_DeleteView(
288             FILE_VIEW *view /* [in] View */
289 ) {
290     if (!(view->flags & VFLAG_SYSTEM))
291         munmap( (void *)view->base, view->size );
292     EnterCriticalSection(&csVirtual);
293     if (view->next) view->next->prev = view->prev;
294     if (view->prev) view->prev->next = view->next;
295     else VIRTUAL_FirstView = view->next;
296     LeaveCriticalSection(&csVirtual);
297     if (view->mapping) NtClose( view->mapping );
298     free( view );
299 }
300
301
302 /***********************************************************************
303  *           VIRTUAL_GetUnixProt
304  *
305  * Convert page protections to protection for mmap/mprotect.
306  */
307 static int VIRTUAL_GetUnixProt( BYTE vprot )
308 {
309     int prot = 0;
310     if ((vprot & VPROT_COMMITTED) && !(vprot & VPROT_GUARD))
311     {
312         if (vprot & VPROT_READ) prot |= PROT_READ;
313         if (vprot & VPROT_WRITE) prot |= PROT_WRITE;
314         if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE;
315         if (vprot & VPROT_EXEC) prot |= PROT_EXEC;
316     }
317     return prot;
318 }
319
320
321 /***********************************************************************
322  *           VIRTUAL_GetWin32Prot
323  *
324  * Convert page protections to Win32 flags.
325  *
326  * RETURNS
327  *      None
328  */
329 static void VIRTUAL_GetWin32Prot(
330             BYTE vprot,     /* [in] Page protection flags */
331             DWORD *protect, /* [out] Location to store Win32 protection flags */
332             DWORD *state    /* [out] Location to store mem state flag */
333 ) {
334     if (protect) {
335         *protect = VIRTUAL_Win32Flags[vprot & 0x0f];
336 /*      if (vprot & VPROT_GUARD) *protect |= PAGE_GUARD;*/
337         if (vprot & VPROT_NOCACHE) *protect |= PAGE_NOCACHE;
338
339         if (vprot & VPROT_GUARD) *protect = PAGE_NOACCESS;
340     }
341
342     if (state) *state = (vprot & VPROT_COMMITTED) ? MEM_COMMIT : MEM_RESERVE;
343 }
344
345
346 /***********************************************************************
347  *           VIRTUAL_GetProt
348  *
349  * Build page protections from Win32 flags.
350  *
351  * RETURNS
352  *      Value of page protection flags
353  */
354 static BYTE VIRTUAL_GetProt(
355             DWORD protect  /* [in] Win32 protection flags */
356 ) {
357     BYTE vprot;
358
359     switch(protect & 0xff)
360     {
361     case PAGE_READONLY:
362         vprot = VPROT_READ;
363         break;
364     case PAGE_READWRITE:
365         vprot = VPROT_READ | VPROT_WRITE;
366         break;
367     case PAGE_WRITECOPY:
368         /* MSDN CreateFileMapping() states that if PAGE_WRITECOPY is given,
369          * that the hFile must have been opened with GENERIC_READ and
370          * GENERIC_WRITE access.  This is WRONG as tests show that you
371          * only need GENERIC_READ access (at least for Win9x,
372          * FIXME: what about NT?).  Thus, we don't put VPROT_WRITE in
373          * PAGE_WRITECOPY and PAGE_EXECUTE_WRITECOPY.
374          */
375         vprot = VPROT_READ | VPROT_WRITECOPY;
376         break;
377     case PAGE_EXECUTE:
378         vprot = VPROT_EXEC;
379         break;
380     case PAGE_EXECUTE_READ:
381         vprot = VPROT_EXEC | VPROT_READ;
382         break;
383     case PAGE_EXECUTE_READWRITE:
384         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITE;
385         break;
386     case PAGE_EXECUTE_WRITECOPY:
387         /* See comment for PAGE_WRITECOPY above */
388         vprot = VPROT_EXEC | VPROT_READ | VPROT_WRITECOPY;
389         break;
390     case PAGE_NOACCESS:
391     default:
392         vprot = 0;
393         break;
394     }
395     if (protect & PAGE_GUARD) vprot |= VPROT_GUARD;
396     if (protect & PAGE_NOCACHE) vprot |= VPROT_NOCACHE;
397     return vprot;
398 }
399
400
401 /***********************************************************************
402  *           VIRTUAL_SetProt
403  *
404  * Change the protection of a range of pages.
405  *
406  * RETURNS
407  *      TRUE: Success
408  *      FALSE: Failure
409  */
410 static BOOL VIRTUAL_SetProt(
411               FILE_VIEW *view, /* [in] Pointer to view */
412               UINT base,     /* [in] Starting address */
413               UINT size,     /* [in] Size in bytes */
414               BYTE vprot       /* [in] Protections to use */
415 ) {
416     TRACE("%08x-%08x %s\n",
417                      base, base + size - 1, VIRTUAL_GetProtStr( vprot ) );
418
419     if (mprotect( (void *)base, size, VIRTUAL_GetUnixProt(vprot) ))
420         return FALSE;  /* FIXME: last error */
421
422     memset( view->prot + ((base - view->base) >> page_shift),
423             vprot, size >> page_shift );
424     VIRTUAL_DEBUG_DUMP_VIEW( view );
425     return TRUE;
426 }
427
428
429 /***********************************************************************
430  *           map_image
431  *
432  * Map an executable (PE format) image into memory.
433  */
434 static LPVOID map_image( HANDLE hmapping, int fd, char *base, DWORD total_size,
435                          DWORD header_size, HANDLE shared_file, DWORD shared_size )
436 {
437     IMAGE_DOS_HEADER *dos;
438     IMAGE_NT_HEADERS *nt;
439     IMAGE_SECTION_HEADER *sec;
440     int i, pos;
441     DWORD err = GetLastError();
442     FILE_VIEW *view = NULL;
443     char *ptr;
444     int shared_fd = -1;
445
446     SetLastError( ERROR_BAD_EXE_FORMAT );  /* generic error */
447
448     /* zero-map the whole range */
449
450     if ((ptr = wine_anon_mmap( base, total_size,
451                              PROT_READ | PROT_WRITE | PROT_EXEC, 0 )) == (char *)-1)
452     {
453         ptr = wine_anon_mmap( NULL, total_size,
454                             PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
455         if (ptr == (char *)-1)
456         {
457             ERR_(module)("Not enough memory for module (%ld bytes)\n", total_size);
458             goto error;
459         }
460     }
461     TRACE_(module)( "mapped PE file at %p-%p\n", ptr, ptr + total_size );
462
463     if (!(view = VIRTUAL_CreateView( (UINT)ptr, total_size, 0,
464                                      VPROT_COMMITTED|VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY,
465                                      hmapping )))
466     {
467         munmap( ptr, total_size );
468         SetLastError( ERROR_OUTOFMEMORY );
469         goto error;
470     }
471
472     /* map the header */
473
474     if (VIRTUAL_mmap( fd, ptr, header_size, 0, PROT_READ | PROT_WRITE,
475                       MAP_PRIVATE | MAP_FIXED ) == (char *)-1) goto error;
476     dos = (IMAGE_DOS_HEADER *)ptr;
477     nt = (IMAGE_NT_HEADERS *)(ptr + dos->e_lfanew);
478     if ((char *)(nt + 1) > ptr + header_size) goto error;
479
480     sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
481     if ((char *)(sec + nt->FileHeader.NumberOfSections) > ptr + header_size) goto error;
482
483     /* check the architecture */
484
485     if (nt->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
486     {
487         MESSAGE("Trying to load PE image for unsupported architecture (");
488         switch (nt->FileHeader.Machine)
489         {
490         case IMAGE_FILE_MACHINE_UNKNOWN: MESSAGE("Unknown"); break;
491         case IMAGE_FILE_MACHINE_I860:    MESSAGE("I860"); break;
492         case IMAGE_FILE_MACHINE_R3000:   MESSAGE("R3000"); break;
493         case IMAGE_FILE_MACHINE_R4000:   MESSAGE("R4000"); break;
494         case IMAGE_FILE_MACHINE_R10000:  MESSAGE("R10000"); break;
495         case IMAGE_FILE_MACHINE_ALPHA:   MESSAGE("Alpha"); break;
496         case IMAGE_FILE_MACHINE_POWERPC: MESSAGE("PowerPC"); break;
497         default: MESSAGE("Unknown-%04x", nt->FileHeader.Machine); break;
498         }
499         MESSAGE(")\n");
500         goto error;
501     }
502     
503     /* retrieve the shared sections file */
504
505     if (shared_size)
506     {
507         if ((shared_fd = FILE_GetUnixHandle( shared_file, GENERIC_READ )) == -1) goto error;
508         CloseHandle( shared_file );  /* we no longer need it */
509         shared_file = 0;
510     }
511
512     /* map all the sections */
513
514     for (i = pos = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
515     {
516         DWORD size;
517
518         /* a few sanity checks */
519         size = sec->VirtualAddress + ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
520         if (sec->VirtualAddress > total_size || size > total_size || size < sec->VirtualAddress)
521         {
522             ERR_(module)( "Section %.8s too large (%lx+%lx/%lx)\n",
523                           sec->Name, sec->VirtualAddress, sec->Misc.VirtualSize, total_size );
524             goto error;
525         }
526
527         if ((sec->Characteristics & IMAGE_SCN_MEM_SHARED) &&
528             (sec->Characteristics & IMAGE_SCN_MEM_WRITE))
529         {
530             size = ROUND_SIZE( 0, sec->Misc.VirtualSize );
531             TRACE_(module)( "mapping shared section %.8s at %p off %lx (%x) size %lx (%lx) flags %lx\n",
532                           sec->Name, (char *)ptr + sec->VirtualAddress,
533                           sec->PointerToRawData, pos, sec->SizeOfRawData,
534                           size, sec->Characteristics );
535             if (VIRTUAL_mmap( shared_fd, (char *)ptr + sec->VirtualAddress, size,
536                               pos, PROT_READ|PROT_WRITE|PROT_EXEC,
537                               MAP_SHARED|MAP_FIXED ) == (void *)-1)
538             {
539                 ERR_(module)( "Could not map shared section %.8s\n", sec->Name );
540                 goto error;
541             }
542             pos += size;
543             continue;
544         }
545
546         if (sec->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue;
547         if (!sec->PointerToRawData || !sec->SizeOfRawData) continue;
548
549         TRACE_(module)( "mapping section %.8s at %p off %lx size %lx flags %lx\n",
550                         sec->Name, (char *)ptr + sec->VirtualAddress,
551                         sec->PointerToRawData, sec->SizeOfRawData,
552                         sec->Characteristics );
553
554         /* Note: if the section is not aligned properly VIRTUAL_mmap will magically
555          *       fall back to read(), so we don't need to check anything here.
556          */
557         if (VIRTUAL_mmap( fd, (char *)ptr + sec->VirtualAddress, sec->SizeOfRawData,
558                           sec->PointerToRawData, PROT_READ|PROT_WRITE|PROT_EXEC,
559                           MAP_PRIVATE | MAP_FIXED ) == (void *)-1)
560         {
561             ERR_(module)( "Could not map section %.8s, file probably truncated\n", sec->Name );
562             goto error;
563         }
564
565         if ((sec->SizeOfRawData < sec->Misc.VirtualSize) && (sec->SizeOfRawData & page_mask))
566         {
567             DWORD end = ROUND_SIZE( 0, sec->SizeOfRawData );
568             if (end > sec->Misc.VirtualSize) end = sec->Misc.VirtualSize;
569             TRACE_(module)("clearing %p - %p\n",
570                            (char *)ptr + sec->VirtualAddress + sec->SizeOfRawData,
571                            (char *)ptr + sec->VirtualAddress + end );
572             memset( (char *)ptr + sec->VirtualAddress + sec->SizeOfRawData, 0,
573                     end - sec->SizeOfRawData );
574         }
575     }
576
577     SetLastError( err );  /* restore last error */
578     close( fd );
579     if (shared_fd != -1) close( shared_fd );
580     return ptr;
581
582  error:
583     if (view) VIRTUAL_DeleteView( view );
584     close( fd );
585     if (shared_fd != -1) close( shared_fd );
586     if (shared_file) CloseHandle( shared_file );
587     return NULL;
588 }
589
590
591 /***********************************************************************
592  *           VIRTUAL_Init
593  */
594 #ifndef page_mask
595 DECL_GLOBAL_CONSTRUCTOR(VIRTUAL_Init)
596 {
597     page_size = getpagesize();
598     page_mask = page_size - 1;
599     /* Make sure we have a power of 2 */
600     assert( !(page_size & page_mask) );
601     page_shift = 0;
602     while ((1 << page_shift) != page_size) page_shift++;
603 }
604 #endif  /* page_mask */
605
606
607 /***********************************************************************
608  *           VIRTUAL_SetFaultHandler
609  */
610 BOOL VIRTUAL_SetFaultHandler( LPCVOID addr, HANDLERPROC proc, LPVOID arg )
611 {
612     FILE_VIEW *view;
613
614     if (!(view = VIRTUAL_FindView((UINT)addr))) return FALSE;
615     view->handlerProc = proc;
616     view->handlerArg  = arg;
617     return TRUE;
618 }
619
620 /***********************************************************************
621  *           VIRTUAL_HandleFault
622  */
623 DWORD VIRTUAL_HandleFault( LPCVOID addr )
624 {
625     FILE_VIEW *view = VIRTUAL_FindView((UINT)addr);
626     DWORD ret = EXCEPTION_ACCESS_VIOLATION;
627
628     if (view)
629     {
630         if (view->handlerProc)
631         {
632             if (view->handlerProc(view->handlerArg, addr)) ret = 0;  /* handled */
633         }
634         else
635         {
636             BYTE vprot = view->prot[((UINT)addr - view->base) >> page_shift];
637             UINT page = (UINT)addr & ~page_mask;
638             char *stack = (char *)NtCurrentTeb()->stack_base + SIGNAL_STACK_SIZE + page_mask + 1;
639             if (vprot & VPROT_GUARD)
640             {
641                 VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD );
642                 ret = STATUS_GUARD_PAGE_VIOLATION;
643             }
644             /* is it inside the stack guard pages? */
645             if (((char *)addr >= stack) && ((char *)addr < stack + 2*(page_mask+1)))
646                 ret = STATUS_STACK_OVERFLOW;
647         }
648     }
649     return ret;
650 }
651
652
653 /***********************************************************************
654  *           VIRTUAL_mmap
655  *
656  * Wrapper for mmap() that handles anonymous mappings portably,
657  * and falls back to read if mmap of a file fails.
658  */
659 static LPVOID VIRTUAL_mmap( int fd, LPVOID start, DWORD size,
660                             DWORD offset, int prot, int flags )
661 {
662     int pos;
663     LPVOID ret;
664
665     if (fd == -1) return wine_anon_mmap( start, size, prot, flags );
666
667     if ((ret = mmap( start, size, prot, flags, fd, offset )) != (LPVOID)-1)
668         return ret;
669
670     /* mmap() failed; if this is because the file offset is not    */
671     /* page-aligned (EINVAL), or because the underlying filesystem */
672     /* does not support mmap() (ENOEXEC,ENODEV), we do it by hand. */
673
674     if ((errno != ENOEXEC) && (errno != EINVAL) && (errno != ENODEV)) return ret;
675     if (prot & PROT_WRITE)
676     {
677         /* We cannot fake shared write mappings */
678 #ifdef MAP_SHARED
679         if (flags & MAP_SHARED) return ret;
680 #endif
681 #ifdef MAP_PRIVATE
682         if (!(flags & MAP_PRIVATE)) return ret;
683 #endif
684     }
685
686     /* Reserve the memory with an anonymous mmap */
687     ret = wine_anon_mmap( start, size, PROT_READ | PROT_WRITE, flags );
688     if (ret == (LPVOID)-1) return ret;
689     /* Now read in the file */
690     if ((pos = lseek( fd, offset, SEEK_SET )) == -1)
691     {
692         munmap( ret, size );
693         return (LPVOID)-1;
694     }
695     read( fd, ret, size );
696     lseek( fd, pos, SEEK_SET );  /* Restore the file pointer */
697     mprotect( ret, size, prot );  /* Set the right protection */
698     return ret;
699 }
700
701
702 /***********************************************************************
703  *             VirtualAlloc   (KERNEL32.548)
704  * Reserves or commits a region of pages in virtual address space
705  *
706  * RETURNS
707  *      Base address of allocated region of pages
708  *      NULL: Failure
709  */
710 LPVOID WINAPI VirtualAlloc(
711               LPVOID addr,  /* [in] Address of region to reserve or commit */
712               DWORD size,   /* [in] Size of region */
713               DWORD type,   /* [in] Type of allocation */
714               DWORD protect /* [in] Type of access protection */
715 ) {
716     FILE_VIEW *view;
717     UINT base, ptr, view_size;
718     BYTE vprot;
719
720     TRACE("%08x %08lx %lx %08lx\n",
721                      (UINT)addr, size, type, protect );
722
723     /* Round parameters to a page boundary */
724
725     if (size > 0x7fc00000)  /* 2Gb - 4Mb */
726     {
727         SetLastError( ERROR_OUTOFMEMORY );
728         return NULL;
729     }
730     if (addr)
731     {
732         if (type & MEM_RESERVE) /* Round down to 64k boundary */
733             base = (UINT)addr & ~granularity_mask;
734         else
735             base = ROUND_ADDR( addr );
736         size = (((UINT)addr + size + page_mask) & ~page_mask) - base;
737         if ((base <= granularity_mask) || (base + size < base))
738         {
739             /* disallow low 64k and wrap-around */
740             SetLastError( ERROR_INVALID_PARAMETER );
741             return NULL;
742         }
743     }
744     else
745     {
746         base = 0;
747         size = (size + page_mask) & ~page_mask;
748     }
749
750     if (type & MEM_TOP_DOWN) {
751         /* FIXME: MEM_TOP_DOWN allocates the largest possible address.
752          *        Is there _ANY_ way to do it with UNIX mmap()?
753          */
754         WARN("MEM_TOP_DOWN ignored\n");
755         type &= ~MEM_TOP_DOWN;
756     }
757     /* Compute the alloc type flags */
758
759     if (!(type & (MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)) ||
760         (type & ~(MEM_COMMIT | MEM_RESERVE | MEM_SYSTEM)))
761     {
762         ERR("called with wrong alloc type flags (%08lx) !\n", type);
763         SetLastError( ERROR_INVALID_PARAMETER );
764         return NULL;
765     }
766     if (type & (MEM_COMMIT | MEM_SYSTEM))
767         vprot = VIRTUAL_GetProt( protect ) | VPROT_COMMITTED;
768     else vprot = 0;
769
770     /* Reserve the memory */
771
772     if ((type & MEM_RESERVE) || !base)
773     {
774         if (type & MEM_SYSTEM)
775         {
776             if (!(view = VIRTUAL_CreateView( base, size, VFLAG_VALLOC | VFLAG_SYSTEM, vprot, 0 )))
777             {
778                 SetLastError( ERROR_OUTOFMEMORY );
779                 return NULL;
780             }
781             return (LPVOID)base;
782         }
783         view_size = size + (base ? 0 : granularity_mask + 1);
784         ptr = (UINT)wine_anon_mmap( (LPVOID)base, view_size, VIRTUAL_GetUnixProt( vprot ), 0 );
785         if (ptr == (UINT)-1)
786         {
787             SetLastError( ERROR_OUTOFMEMORY );
788             return NULL;
789         }
790         if (!base)
791         {
792             /* Release the extra memory while keeping the range */
793             /* starting on a 64k boundary. */
794
795             if (ptr & granularity_mask)
796             {
797                 UINT extra = granularity_mask + 1 - (ptr & granularity_mask);
798                 munmap( (void *)ptr, extra );
799                 ptr += extra;
800                 view_size -= extra;
801             }
802             if (view_size > size)
803                 munmap( (void *)(ptr + size), view_size - size );
804         }
805         else if (ptr != base)
806         {
807             /* We couldn't get the address we wanted */
808             munmap( (void *)ptr, view_size );
809             SetLastError( ERROR_INVALID_ADDRESS );
810             return NULL;
811         }
812         if (!(view = VIRTUAL_CreateView( ptr, size, VFLAG_VALLOC, vprot, 0 )))
813         {
814             munmap( (void *)ptr, size );
815             SetLastError( ERROR_OUTOFMEMORY );
816             return NULL;
817         }
818         return (LPVOID)ptr;
819     }
820
821     /* Commit the pages */
822
823     if (!(view = VIRTUAL_FindView( base )) ||
824         (base + size > view->base + view->size))
825     {
826         SetLastError( ERROR_INVALID_ADDRESS );
827         return NULL;
828     }
829
830     if (!VIRTUAL_SetProt( view, base, size, vprot )) return NULL;
831     return (LPVOID)base;
832 }
833
834
835 /***********************************************************************
836  *             VirtualAllocEx   (KERNEL32.548)
837  *
838  * Seems to be just as VirtualAlloc, but with process handle.
839  */
840 LPVOID WINAPI VirtualAllocEx(
841               HANDLE hProcess, /* [in] Handle of process to do mem operation */
842               LPVOID addr,  /* [in] Address of region to reserve or commit */
843               DWORD size,   /* [in] Size of region */
844               DWORD type,   /* [in] Type of allocation */
845               DWORD protect /* [in] Type of access protection */
846 ) {
847     if (MapProcessHandle( hProcess ) == GetCurrentProcessId())
848         return VirtualAlloc( addr, size, type, protect );
849     ERR("Unsupported on other process\n");
850     return NULL;
851 }
852
853
854 /***********************************************************************
855  *             VirtualFree   (KERNEL32.550)
856  * Release or decommits a region of pages in virtual address space.
857  * 
858  * RETURNS
859  *      TRUE: Success
860  *      FALSE: Failure
861  */
862 BOOL WINAPI VirtualFree(
863               LPVOID addr, /* [in] Address of region of committed pages */
864               DWORD size,  /* [in] Size of region */
865               DWORD type   /* [in] Type of operation */
866 ) {
867     FILE_VIEW *view;
868     UINT base;
869
870     TRACE("%08x %08lx %lx\n",
871                      (UINT)addr, size, type );
872
873     /* Fix the parameters */
874
875     size = ROUND_SIZE( addr, size );
876     base = ROUND_ADDR( addr );
877
878     if (!(view = VIRTUAL_FindView( base )) ||
879         (base + size > view->base + view->size) ||
880         !(view->flags & VFLAG_VALLOC))
881     {
882         SetLastError( ERROR_INVALID_PARAMETER );
883         return FALSE;
884     }
885
886     /* Compute the protection flags */
887
888     if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
889     {
890         ERR("called with wrong free type flags (%08lx) !\n", type);
891         SetLastError( ERROR_INVALID_PARAMETER );
892         return FALSE;
893     }
894
895     /* Free the pages */
896
897     if (type == MEM_RELEASE)
898     {
899         if (size || (base != view->base))
900         {
901             SetLastError( ERROR_INVALID_PARAMETER );
902             return FALSE;
903         }
904         VIRTUAL_DeleteView( view );
905         return TRUE;
906     }
907
908     /* Decommit the pages by remapping zero-pages instead */
909
910     if (wine_anon_mmap( (LPVOID)base, size, VIRTUAL_GetUnixProt(0), MAP_FIXED ) != (LPVOID)base)
911         ERR( "Could not remap pages, expect trouble\n" );
912     return VIRTUAL_SetProt( view, base, size, 0 );
913 }
914
915
916 /***********************************************************************
917  *             VirtualLock   (KERNEL32.551)
918  * Locks the specified region of virtual address space
919  * 
920  * NOTE
921  *      Always returns TRUE
922  *
923  * RETURNS
924  *      TRUE: Success
925  *      FALSE: Failure
926  */
927 BOOL WINAPI VirtualLock(
928               LPVOID addr, /* [in] Address of first byte of range to lock */
929               DWORD size   /* [in] Number of bytes in range to lock */
930 ) {
931     return TRUE;
932 }
933
934
935 /***********************************************************************
936  *             VirtualUnlock   (KERNEL32.556)
937  * Unlocks a range of pages in the virtual address space
938  *
939  * NOTE
940  *      Always returns TRUE
941  *
942  * RETURNS
943  *      TRUE: Success
944  *      FALSE: Failure
945  */
946 BOOL WINAPI VirtualUnlock(
947               LPVOID addr, /* [in] Address of first byte of range */
948               DWORD size   /* [in] Number of bytes in range */
949 ) {
950     return TRUE;
951 }
952
953
954 /***********************************************************************
955  *             VirtualProtect   (KERNEL32.552)
956  * Changes the access protection on a region of committed pages
957  *
958  * RETURNS
959  *      TRUE: Success
960  *      FALSE: Failure
961  */
962 BOOL WINAPI VirtualProtect(
963               LPVOID addr,     /* [in] Address of region of committed pages */
964               DWORD size,      /* [in] Size of region */
965               DWORD new_prot,  /* [in] Desired access protection */
966               LPDWORD old_prot /* [out] Address of variable to get old protection */
967 ) {
968     FILE_VIEW *view;
969     UINT base, i;
970     BYTE vprot, *p;
971     DWORD prot;
972
973     TRACE("%08x %08lx %08lx\n",
974                      (UINT)addr, size, new_prot );
975
976     /* Fix the parameters */
977
978     size = ROUND_SIZE( addr, size );
979     base = ROUND_ADDR( addr );
980
981     if (!(view = VIRTUAL_FindView( base )) ||
982         (base + size > view->base + view->size))
983     {
984         SetLastError( ERROR_INVALID_PARAMETER );
985         return FALSE;
986     }
987
988     /* Make sure all the pages are committed */
989
990     p = view->prot + ((base - view->base) >> page_shift);
991     VIRTUAL_GetWin32Prot( *p, &prot, NULL );
992     for (i = size >> page_shift; i; i--, p++)
993     {
994         if (!(*p & VPROT_COMMITTED))
995         {
996             SetLastError( ERROR_INVALID_PARAMETER );
997             return FALSE;
998         }
999     }
1000
1001     if (old_prot) *old_prot = prot;
1002     vprot = VIRTUAL_GetProt( new_prot ) | VPROT_COMMITTED;
1003     return VIRTUAL_SetProt( view, base, size, vprot );
1004 }
1005
1006
1007 /***********************************************************************
1008  *             VirtualProtectEx   (KERNEL32.553)
1009  * Changes the access protection on a region of committed pages in the
1010  * virtual address space of a specified process
1011  *
1012  * RETURNS
1013  *      TRUE: Success
1014  *      FALSE: Failure
1015  */
1016 BOOL WINAPI VirtualProtectEx(
1017               HANDLE handle, /* [in]  Handle of process */
1018               LPVOID addr,     /* [in]  Address of region of committed pages */
1019               DWORD size,      /* [in]  Size of region */
1020               DWORD new_prot,  /* [in]  Desired access protection */
1021               LPDWORD old_prot /* [out] Address of variable to get old protection */ )
1022 {
1023     if (MapProcessHandle( handle ) == GetCurrentProcessId())
1024         return VirtualProtect( addr, size, new_prot, old_prot );
1025     ERR("Unsupported on other process\n");
1026     return FALSE;
1027 }
1028
1029
1030 /***********************************************************************
1031  *             VirtualQuery   (KERNEL32.554)
1032  * Provides info about a range of pages in virtual address space
1033  *
1034  * RETURNS
1035  *      Number of bytes returned in information buffer
1036  *      or 0 if addr is >= 0xc0000000 (kernel space).
1037  */
1038 DWORD WINAPI VirtualQuery(
1039              LPCVOID addr,                    /* [in]  Address of region */
1040              LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
1041              DWORD len                        /* [in]  Size of buffer */
1042 ) {
1043     FILE_VIEW *view;
1044     UINT base;
1045     UINT alloc_base = 0;
1046     UINT size = 0;
1047
1048     if (addr >= (void*)0xc0000000) return 0;
1049
1050     base = ROUND_ADDR( addr );
1051
1052     /* Find the view containing the address */
1053
1054     EnterCriticalSection(&csVirtual);
1055     view = VIRTUAL_FirstView;
1056     for (;;)
1057     {
1058         if (!view)
1059         {
1060             size = 0xffff0000 - alloc_base;
1061             break;
1062         }
1063         if (view->base > base)
1064         {
1065             size = view->base - alloc_base;
1066             view = NULL;
1067             break;
1068         }
1069         if (view->base + view->size > base)
1070         {
1071             alloc_base = view->base;
1072             size = view->size;
1073             break;
1074         }
1075         alloc_base = view->base + view->size;
1076         view = view->next;
1077     }
1078     LeaveCriticalSection(&csVirtual);
1079
1080     /* Fill the info structure */
1081
1082     if (!view)
1083     {
1084         info->State             = MEM_FREE;
1085         info->Protect           = 0;
1086         info->AllocationProtect = 0;
1087         info->Type              = 0;
1088     }
1089     else
1090     {
1091         BYTE vprot = view->prot[(base - alloc_base) >> page_shift];
1092         VIRTUAL_GetWin32Prot( vprot, &info->Protect, &info->State );
1093         for (size = base - alloc_base; size < view->size; size += page_mask+1)
1094             if (view->prot[size >> page_shift] != vprot) break;
1095         info->AllocationProtect = view->protect;
1096         info->Type              = MEM_PRIVATE;  /* FIXME */
1097     }
1098
1099     info->BaseAddress    = (LPVOID)base;
1100     info->AllocationBase = (LPVOID)alloc_base;
1101     info->RegionSize     = size - (base - alloc_base);
1102     return sizeof(*info);
1103 }
1104
1105
1106 /***********************************************************************
1107  *             VirtualQueryEx   (KERNEL32.555)
1108  * Provides info about a range of pages in virtual address space of a
1109  * specified process
1110  *
1111  * RETURNS
1112  *      Number of bytes returned in information buffer
1113  */
1114 DWORD WINAPI VirtualQueryEx(
1115              HANDLE handle,                 /* [in] Handle of process */
1116              LPCVOID addr,                    /* [in] Address of region */
1117              LPMEMORY_BASIC_INFORMATION info, /* [out] Address of info buffer */
1118              DWORD len                        /* [in] Size of buffer */ )
1119 {
1120     if (MapProcessHandle( handle ) == GetCurrentProcessId())
1121         return VirtualQuery( addr, info, len );
1122     ERR("Unsupported on other process\n");
1123     return 0;
1124 }
1125
1126
1127 /***********************************************************************
1128  *             IsBadReadPtr   (KERNEL32.354)
1129  *
1130  * RETURNS
1131  *      FALSE: Process has read access to entire block
1132  *      TRUE: Otherwise
1133  */
1134 BOOL WINAPI IsBadReadPtr(
1135               LPCVOID ptr, /* [in] Address of memory block */
1136               UINT size )  /* [in] Size of block */
1137 {
1138     if (!size) return FALSE;  /* handle 0 size case w/o reference */
1139     __TRY
1140     {
1141         volatile const char *p = ptr;
1142         char dummy;
1143         UINT count = size;
1144
1145         while (count > page_size)
1146         {
1147             dummy = *p;
1148             p += page_size;
1149             count -= page_size;
1150         }
1151         dummy = p[0];
1152         dummy = p[count - 1];
1153     }
1154     __EXCEPT(page_fault) { return TRUE; }
1155     __ENDTRY
1156     return FALSE;
1157 }
1158
1159
1160 /***********************************************************************
1161  *             IsBadWritePtr   (KERNEL32.357)
1162  *
1163  * RETURNS
1164  *      FALSE: Process has write access to entire block
1165  *      TRUE: Otherwise
1166  */
1167 BOOL WINAPI IsBadWritePtr(
1168               LPVOID ptr, /* [in] Address of memory block */
1169               UINT size ) /* [in] Size of block in bytes */
1170 {
1171     if (!size) return FALSE;  /* handle 0 size case w/o reference */
1172     __TRY
1173     {
1174         volatile char *p = ptr;
1175         UINT count = size;
1176
1177         while (count > page_size)
1178         {
1179             *p |= 0;
1180             p += page_size;
1181             count -= page_size;
1182         }
1183         p[0] |= 0;
1184         p[count - 1] |= 0;
1185     }
1186     __EXCEPT(page_fault) { return TRUE; }
1187     __ENDTRY
1188     return FALSE;
1189 }
1190
1191
1192 /***********************************************************************
1193  *             IsBadHugeReadPtr   (KERNEL32.352)
1194  * RETURNS
1195  *      FALSE: Process has read access to entire block
1196  *      TRUE: Otherwise
1197  */
1198 BOOL WINAPI IsBadHugeReadPtr(
1199               LPCVOID ptr, /* [in] Address of memory block */
1200               UINT size  /* [in] Size of block */
1201 ) {
1202     return IsBadReadPtr( ptr, size );
1203 }
1204
1205
1206 /***********************************************************************
1207  *             IsBadHugeWritePtr   (KERNEL32.353)
1208  * RETURNS
1209  *      FALSE: Process has write access to entire block
1210  *      TRUE: Otherwise
1211  */
1212 BOOL WINAPI IsBadHugeWritePtr(
1213               LPVOID ptr, /* [in] Address of memory block */
1214               UINT size /* [in] Size of block */
1215 ) {
1216     return IsBadWritePtr( ptr, size );
1217 }
1218
1219
1220 /***********************************************************************
1221  *             IsBadCodePtr   (KERNEL32.351)
1222  *
1223  * RETURNS
1224  *      FALSE: Process has read access to specified memory
1225  *      TRUE: Otherwise
1226  */
1227 BOOL WINAPI IsBadCodePtr( FARPROC ptr ) /* [in] Address of function */
1228 {
1229     return IsBadReadPtr( ptr, 1 );
1230 }
1231
1232
1233 /***********************************************************************
1234  *             IsBadStringPtrA   (KERNEL32.355)
1235  *
1236  * RETURNS
1237  *      FALSE: Read access to all bytes in string
1238  *      TRUE: Else
1239  */
1240 BOOL WINAPI IsBadStringPtrA(
1241               LPCSTR str, /* [in] Address of string */
1242               UINT max )  /* [in] Maximum size of string */
1243 {
1244     __TRY
1245     {
1246         volatile const char *p = str;
1247         while (p != str + max) if (!*p++) break;
1248     }
1249     __EXCEPT(page_fault) { return TRUE; }
1250     __ENDTRY
1251     return FALSE;
1252 }
1253
1254
1255 /***********************************************************************
1256  *             IsBadStringPtrW   (KERNEL32.356)
1257  * See IsBadStringPtrA
1258  */
1259 BOOL WINAPI IsBadStringPtrW( LPCWSTR str, UINT max )
1260 {
1261     __TRY
1262     {
1263         volatile const WCHAR *p = str;
1264         while (p != str + max) if (!*p++) break;
1265     }
1266     __EXCEPT(page_fault) { return TRUE; }
1267     __ENDTRY
1268     return FALSE;
1269 }
1270
1271
1272 /***********************************************************************
1273  *             CreateFileMappingA   (KERNEL32.46)
1274  * Creates a named or unnamed file-mapping object for the specified file
1275  *
1276  * RETURNS
1277  *      Handle: Success
1278  *      0: Mapping object does not exist
1279  *      NULL: Failure
1280  */
1281 HANDLE WINAPI CreateFileMappingA(
1282                 HANDLE hFile,   /* [in] Handle of file to map */
1283                 SECURITY_ATTRIBUTES *sa, /* [in] Optional security attributes*/
1284                 DWORD protect,   /* [in] Protection for mapping object */
1285                 DWORD size_high, /* [in] High-order 32 bits of object size */
1286                 DWORD size_low,  /* [in] Low-order 32 bits of object size */
1287                 LPCSTR name      /* [in] Name of file-mapping object */ )
1288 {
1289     HANDLE ret;
1290     BYTE vprot;
1291     DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0;
1292
1293     /* Check parameters */
1294
1295     TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
1296           hFile, sa, protect, size_high, size_low, debugstr_a(name) );
1297
1298     if (len > MAX_PATH)
1299     {
1300         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1301         return 0;
1302     }
1303     vprot = VIRTUAL_GetProt( protect );
1304     if (protect & SEC_RESERVE)
1305     {
1306         if (hFile != INVALID_HANDLE_VALUE)
1307         {
1308             SetLastError( ERROR_INVALID_PARAMETER );
1309             return 0;
1310         }
1311     }
1312     else vprot |= VPROT_COMMITTED;
1313     if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
1314     if (protect & SEC_IMAGE) vprot |= VPROT_IMAGE;
1315
1316     /* Create the server object */
1317
1318     if (hFile == INVALID_HANDLE_VALUE) hFile = 0;
1319     SERVER_START_VAR_REQ( create_mapping, len * sizeof(WCHAR) )
1320     {
1321         req->file_handle = hFile;
1322         req->size_high   = size_high;
1323         req->size_low    = size_low;
1324         req->protect     = vprot;
1325         req->inherit     = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
1326         if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len );
1327         SetLastError(0);
1328         SERVER_CALL_ERR();
1329         ret = req->handle;
1330     }
1331     SERVER_END_VAR_REQ;
1332     return ret;
1333 }
1334
1335
1336 /***********************************************************************
1337  *             CreateFileMappingW   (KERNEL32.47)
1338  * See CreateFileMappingA
1339  */
1340 HANDLE WINAPI CreateFileMappingW( HANDLE hFile, LPSECURITY_ATTRIBUTES sa, 
1341                                   DWORD protect, DWORD size_high,  
1342                                   DWORD size_low, LPCWSTR name )
1343 {
1344     HANDLE ret;
1345     BYTE vprot;
1346     DWORD len = name ? strlenW(name) : 0;
1347
1348     /* Check parameters */
1349
1350     TRACE("(%x,%p,%08lx,%08lx%08lx,%s)\n",
1351           hFile, sa, protect, size_high, size_low, debugstr_w(name) );
1352
1353     if (len > MAX_PATH)
1354     {
1355         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1356         return 0;
1357     }
1358
1359     vprot = VIRTUAL_GetProt( protect );
1360     if (protect & SEC_RESERVE)
1361     {
1362         if (hFile != INVALID_HANDLE_VALUE)
1363         {
1364             SetLastError( ERROR_INVALID_PARAMETER );
1365             return 0;
1366         }
1367     }
1368     else vprot |= VPROT_COMMITTED;
1369     if (protect & SEC_NOCACHE) vprot |= VPROT_NOCACHE;
1370     if (protect & SEC_IMAGE) vprot |= VPROT_IMAGE;
1371
1372     /* Create the server object */
1373
1374     if (hFile == INVALID_HANDLE_VALUE) hFile = 0;
1375     SERVER_START_VAR_REQ( create_mapping, len * sizeof(WCHAR) )
1376     {
1377         req->file_handle = hFile;
1378         req->size_high   = size_high;
1379         req->size_low    = size_low;
1380         req->protect     = vprot;
1381         req->inherit     = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
1382         memcpy( server_data_ptr(req), name, len * sizeof(WCHAR) );
1383         SetLastError(0);
1384         SERVER_CALL_ERR();
1385         ret = req->handle;
1386     }
1387     SERVER_END_VAR_REQ;
1388     return ret;
1389 }
1390
1391
1392 /***********************************************************************
1393  *             OpenFileMappingA   (KERNEL32.397)
1394  * Opens a named file-mapping object.
1395  *
1396  * RETURNS
1397  *      Handle: Success
1398  *      NULL: Failure
1399  */
1400 HANDLE WINAPI OpenFileMappingA(
1401                 DWORD access,   /* [in] Access mode */
1402                 BOOL inherit, /* [in] Inherit flag */
1403                 LPCSTR name )   /* [in] Name of file-mapping object */
1404 {
1405     HANDLE ret;
1406     DWORD len = name ? MultiByteToWideChar( CP_ACP, 0, name, strlen(name), NULL, 0 ) : 0;
1407     if (len > MAX_PATH)
1408     {
1409         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1410         return 0;
1411     }
1412     SERVER_START_VAR_REQ( open_mapping, len * sizeof(WCHAR) )
1413     {
1414         req->access  = access;
1415         req->inherit = inherit;
1416         if (len) MultiByteToWideChar( CP_ACP, 0, name, strlen(name), server_data_ptr(req), len );
1417         SERVER_CALL_ERR();
1418         ret = req->handle;
1419     }
1420     SERVER_END_VAR_REQ;
1421     return ret;
1422 }
1423
1424
1425 /***********************************************************************
1426  *             OpenFileMappingW   (KERNEL32.398)
1427  * See OpenFileMappingA
1428  */
1429 HANDLE WINAPI OpenFileMappingW( DWORD access, BOOL inherit, LPCWSTR name)
1430 {
1431     HANDLE ret;
1432     DWORD len = name ? strlenW(name) : 0;
1433     if (len > MAX_PATH)
1434     {
1435         SetLastError( ERROR_FILENAME_EXCED_RANGE );
1436         return 0;
1437     }
1438     SERVER_START_VAR_REQ( open_mapping, len * sizeof(WCHAR) )
1439     {
1440         req->access  = access;
1441         req->inherit = inherit;
1442         memcpy( server_data_ptr(req), name, len * sizeof(WCHAR) );
1443         SERVER_CALL_ERR();
1444         ret = req->handle;
1445     }
1446     SERVER_END_VAR_REQ;
1447     return ret;
1448 }
1449
1450
1451 /***********************************************************************
1452  *             MapViewOfFile   (KERNEL32.385)
1453  * Maps a view of a file into the address space
1454  *
1455  * RETURNS
1456  *      Starting address of mapped view
1457  *      NULL: Failure
1458  */
1459 LPVOID WINAPI MapViewOfFile(
1460               HANDLE mapping,  /* [in] File-mapping object to map */
1461               DWORD access,      /* [in] Access mode */
1462               DWORD offset_high, /* [in] High-order 32 bits of file offset */
1463               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
1464               DWORD count        /* [in] Number of bytes to map */
1465 ) {
1466     return MapViewOfFileEx( mapping, access, offset_high,
1467                             offset_low, count, NULL );
1468 }
1469
1470
1471 /***********************************************************************
1472  *             MapViewOfFileEx   (KERNEL32.386)
1473  * Maps a view of a file into the address space
1474  *
1475  * RETURNS
1476  *      Starting address of mapped view
1477  *      NULL: Failure
1478  */
1479 LPVOID WINAPI MapViewOfFileEx(
1480               HANDLE handle,   /* [in] File-mapping object to map */
1481               DWORD access,      /* [in] Access mode */
1482               DWORD offset_high, /* [in] High-order 32 bits of file offset */
1483               DWORD offset_low,  /* [in] Low-order 32 bits of file offset */
1484               DWORD count,       /* [in] Number of bytes to map */
1485               LPVOID addr        /* [in] Suggested starting address for mapped view */
1486 ) {
1487     FILE_VIEW *view;
1488     UINT ptr = (UINT)-1, size = 0;
1489     int flags = MAP_PRIVATE;
1490     int unix_handle = -1;
1491     int prot, res;
1492     void *base;
1493     DWORD size_low, size_high, header_size, shared_size;
1494     HANDLE shared_file;
1495
1496     /* Check parameters */
1497
1498     if ((offset_low & granularity_mask) ||
1499         (addr && ((UINT)addr & granularity_mask)))
1500     {
1501         SetLastError( ERROR_INVALID_PARAMETER );
1502         return NULL;
1503     }
1504
1505     SERVER_START_REQ( get_mapping_info )
1506     {
1507         req->handle = handle;
1508         res = SERVER_CALL_ERR();
1509         prot        = req->protect;
1510         base        = req->base;
1511         size_low    = req->size_low;
1512         size_high   = req->size_high;
1513         header_size = req->header_size;
1514         shared_file = req->shared_file;
1515         shared_size = req->shared_size;
1516     }
1517     SERVER_END_REQ;
1518     if (res) goto error;
1519
1520     if ((unix_handle = FILE_GetUnixHandle( handle, 0 )) == -1) goto error;
1521
1522     if (prot & VPROT_IMAGE)
1523         return map_image( handle, unix_handle, base, size_low, header_size,
1524                           shared_file, shared_size );
1525
1526
1527     if (size_high || offset_high)
1528         ERR("Offsets larger than 4Gb not supported\n");
1529
1530     if ((offset_low >= size_low) ||
1531         (count > size_low - offset_low))
1532     {
1533         SetLastError( ERROR_INVALID_PARAMETER );
1534         goto error;
1535     }
1536     if (count) size = ROUND_SIZE( offset_low, count );
1537     else size = size_low - offset_low;
1538
1539     switch(access)
1540     {
1541     case FILE_MAP_ALL_ACCESS:
1542     case FILE_MAP_WRITE:
1543     case FILE_MAP_WRITE | FILE_MAP_READ:
1544         if (!(prot & VPROT_WRITE))
1545         {
1546             SetLastError( ERROR_INVALID_PARAMETER );
1547             goto error;
1548         }
1549         flags = MAP_SHARED;
1550         /* fall through */
1551     case FILE_MAP_READ:
1552     case FILE_MAP_COPY:
1553     case FILE_MAP_COPY | FILE_MAP_READ:
1554         if (prot & VPROT_READ) break;
1555         /* fall through */
1556     default:
1557         SetLastError( ERROR_INVALID_PARAMETER );
1558         goto error;
1559     }
1560
1561     /* FIXME: If a mapping is created with SEC_RESERVE and a process,
1562      * which has a view of this mapping commits some pages, they will
1563      * appear commited in all other processes, which have the same
1564      * view created. Since we don`t support this yet, we create the
1565      * whole mapping commited.
1566      */
1567     prot |= VPROT_COMMITTED;
1568
1569     /* Map the file */
1570
1571     TRACE("handle=%x size=%x offset=%lx\n", handle, size, offset_low );
1572
1573     ptr = (UINT)VIRTUAL_mmap( unix_handle, addr, size, offset_low,
1574                               VIRTUAL_GetUnixProt( prot ), flags );
1575     if (ptr == (UINT)-1) {
1576         /* KB: Q125713, 25-SEP-1995, "Common File Mapping Problems and
1577          * Platform Differences": 
1578          * Windows NT: ERROR_INVALID_PARAMETER
1579          * Windows 95: ERROR_INVALID_ADDRESS.
1580          */
1581         if (errno==ENOMEM)
1582             SetLastError( ERROR_OUTOFMEMORY );
1583         else
1584         {
1585             if (GetVersion() & 0x80000000)  /* win95 */
1586             {
1587                 TRACE("setting ERROR_INVALID_ADDRESS for WinXX\n");
1588                 SetLastError( ERROR_INVALID_ADDRESS );
1589             }
1590             else
1591             {
1592                 TRACE("setting ERROR_INVALID_PARAMETER for NTXX\n");
1593                 SetLastError( ERROR_INVALID_PARAMETER );
1594             }
1595         }
1596         goto error;
1597     }
1598
1599     if (!(view = VIRTUAL_CreateView( ptr, size, 0, prot, handle )))
1600     {
1601         SetLastError( ERROR_OUTOFMEMORY );
1602         goto error;
1603     }
1604     if (unix_handle != -1) close( unix_handle );
1605     return (LPVOID)ptr;
1606
1607 error:
1608     if (unix_handle != -1) close( unix_handle );
1609     if (ptr != (UINT)-1) munmap( (void *)ptr, size );
1610     return NULL;
1611 }
1612
1613
1614 /***********************************************************************
1615  *             FlushViewOfFile   (KERNEL32.262)
1616  * Writes to the disk a byte range within a mapped view of a file
1617  *
1618  * RETURNS
1619  *      TRUE: Success
1620  *      FALSE: Failure
1621  */
1622 BOOL WINAPI FlushViewOfFile(
1623               LPCVOID base, /* [in] Start address of byte range to flush */
1624               DWORD cbFlush /* [in] Number of bytes in range */
1625 ) {
1626     FILE_VIEW *view;
1627     UINT addr = ROUND_ADDR( base );
1628
1629     TRACE("FlushViewOfFile at %p for %ld bytes\n",
1630                      base, cbFlush );
1631
1632     if (!(view = VIRTUAL_FindView( addr )))
1633     {
1634         SetLastError( ERROR_INVALID_PARAMETER );
1635         return FALSE;
1636     }
1637     if (!cbFlush) cbFlush = view->size;
1638     if (!msync( (void *)addr, cbFlush, MS_SYNC )) return TRUE;
1639     SetLastError( ERROR_INVALID_PARAMETER );
1640     return FALSE;
1641 }
1642
1643
1644 /***********************************************************************
1645  *             UnmapViewOfFile   (KERNEL32.540)
1646  * Unmaps a mapped view of a file.
1647  *
1648  * NOTES
1649  *      Should addr be an LPCVOID?
1650  *
1651  * RETURNS
1652  *      TRUE: Success
1653  *      FALSE: Failure
1654  */
1655 BOOL WINAPI UnmapViewOfFile(
1656               LPVOID addr /* [in] Address where mapped view begins */
1657 ) {
1658     FILE_VIEW *view;
1659     UINT base = ROUND_ADDR( addr );
1660     if (!(view = VIRTUAL_FindView( base )) || (base != view->base))
1661     {
1662         SetLastError( ERROR_INVALID_PARAMETER );
1663         return FALSE;
1664     }
1665     VIRTUAL_DeleteView( view );
1666     return TRUE;
1667 }